[python] Python sqlite3 및 동시성

“스레딩”모듈을 사용하는 Python 프로그램이 있습니다. 매초마다 내 프로그램은 웹에서 일부 데이터를 가져 와서이 데이터를 내 하드 드라이브에 저장하는 새 스레드를 시작합니다. 이 결과를 저장하기 위해 sqlite3를 사용하고 싶지만 작동 할 수 없습니다. 문제는 다음 줄에 관한 것 같습니다.

conn = sqlite3.connect("mydatabase.db")
  • 이 코드 줄을 각 스레드에 넣으면 데이터베이스 파일이 잠겨 있음을 알려주는 OperationalError가 발생합니다. 이것은 다른 스레드가 sqlite3 연결을 통해 mydatabase.db를 열고 잠겨 있음을 의미합니다.
  • 이 코드 줄을 주 프로그램에 넣고 연결 개체 (conn)를 각 스레드에 전달하면 스레드에서 생성 된 SQLite 개체는 동일한 스레드에서만 사용할 수 있다는 ProgrammingError가 발생합니다.

이전에는 모든 결과를 CSV 파일에 저장했지만 이러한 파일 잠금 문제가 없었습니다. 바라건대 이것은 sqlite로 가능할 것입니다. 어떤 아이디어?



답변

소비자-생산자 패턴을 사용할 수 있습니다. 예를 들어 스레드간에 공유되는 대기열을 만들 수 있습니다. 웹에서 데이터를 가져 오는 첫 번째 스레드는이 데이터를 공유 큐에 넣습니다. 데이터베이스 연결을 소유 한 다른 스레드는 큐에서 데이터를 빼고 데이터베이스로 전달합니다.


답변

대중적인 믿음과는 달리, 최신 버전의 sqlite3 다중 스레드에서의 액세스를 지원합니다.

선택적 키워드 인수를 통해 활성화 할 수 있습니다 check_same_thread.

sqlite.connect(":memory:", check_same_thread=False)


답변

다음은 mail.python.org.pipermail.1239789

에서 발견되었습니다. 해결책을 찾았습니다. 파이썬 문서에이 옵션에 대해 한 마디도없는 이유를 모르겠습니다. 따라서 연결 함수에 새 키워드 인수를 추가해야하며 다른 스레드에서 커서를 만들 수 있습니다. 따라서 다음을 사용하십시오.

sqlite.connect(":memory:", check_same_thread = False)

나를 위해 완벽하게 작동합니다. 물론 지금부터 db에 대한 안전한 멀티 스레딩 액세스를 처리해야합니다. 어쨌든 도움을 주신 모든 분들께 감사드립니다.


답변

다중 처리로 전환하십시오 . 훨씬 더 좋고 확장 성이 뛰어나며 여러 CPU를 사용하여 여러 코어를 사용할 수 있으며 인터페이스는 파이썬 스레딩 모듈을 사용하는 것과 동일합니다.

또는 Ali가 제안했듯이 SQLAlchemy의 스레드 풀링 메커니즘을 사용하십시오 . 자동으로 모든 것을 처리하고 몇 가지 추가 기능을 제공합니다.

  1. SQLAlchemy는 SQLite, Postgres, MySQL, Oracle, MS-SQL, Firebird, MaxDB, MS Access, Sybase 및 Informix 용 방언을 포함합니다. IBM은 DB2 드라이버도 출시했습니다. 따라서 SQLite에서 벗어나기로 결정한 경우 애플리케이션을 다시 작성할 필요가 없습니다.
  2. SQLAlchemy의 ORM (Object Relational Mapper)의 중심 부분 인 작업 단위 시스템은 보류중인 생성 / 삽입 / 업데이트 / 삭제 작업을 대기열로 구성하고 모든 작업을 한 번에 플러시합니다. 이를 수행하기 위해 큐에있는 모든 수정 된 항목의 토폴로지 “종속성 정렬”을 수행하여 외래 키 제약 조건을 준수하고 중복 문을 그룹화하여 때때로 추가로 일괄 처리 할 수 ​​있습니다. 이는 최대의 효율성과 트랜잭션 안전성을 제공하고 교착 상태의 가능성을 최소화합니다.


답변

이를 위해 스레드를 전혀 사용해서는 안됩니다. 이것은 꼬인 사람 에게는 사소한 작업이며 어쨌든 훨씬 더 나아갈 것입니다.

하나의 스레드 만 사용하고 요청이 완료되면 쓰기를 수행하는 이벤트를 트리거합니다.

twisted는 예약, 콜백 등을 처리합니다. 전체 결과를 문자열로 전달하거나 스트림 프로세서를 통해 실행할 수 있습니다 ( 결과가 아직 다운로드되는 동안 호출자에게 이벤트를 발생 시키는 Twitter APIfriendfeed API 가 있습니다).

데이터로 수행하는 작업에 따라 전체 결과를 sqlite에 완료 한 후 덤프하거나, 쿠킹하고 덤프하거나, 읽는 동안 쿠킹하고 마지막에 덤프 할 수 있습니다.

github에서 원하는 것과 비슷한 작업을 수행하는 매우 간단한 응용 프로그램이 있습니다. 나는 그것을 pfetch (병렬 가져 오기) 라고 부른다 . 일정에 따라 다양한 페이지를 가져오고 결과를 파일로 스트리밍하며 각 페이지가 성공적으로 완료되면 선택적으로 스크립트를 실행합니다. 또한 조건부 GET과 같은 멋진 작업을 수행하지만 여전히 수행중인 작업에 대한 좋은 기반이 될 수 있습니다.


답변

또는 저처럼 게으르다면 SQLAlchemy 를 사용할 수 있습니다 . 스레드 로컬 및 일부 연결 풀링을 사용하여 스레딩을 처리하고 구성 방법도 가능 합니다 .

추가 보너스로, 동시 애플리케이션에 Sqlite를 사용하는 것이 재앙이 될 것이라는 사실을 깨닫거나 결정할 때 MySQL, Postgres 또는 다른 것을 사용하기 위해 코드를 변경할 필요가 없습니다. 그냥 전환 할 수 있습니다.


답변

당신은 사용할 필요가 session.close()이후 모든 트랜잭션 이 오류가 발생할 다중 스레드에서 같은 커서를 사용하지 않는 동일한 스레드에서 같은 커서를 사용하기 위해 데이터베이스에.