2009-10-08 5 views
10

문제점 :pyodbc로 파이썬 다중 처리 및 데이터베이스 액세스가 "안전하지 않습니다"?

나는 다음 역 추적을 얻고 그것이 무엇을 의미하는지 이해하지 못하거나 그것을 해결하는 방법 :

Traceback (most recent call last): 
    File "<string>", line 1, in <module> 
    File "C:\Python26\lib\multiprocessing\forking.py", line 342, in main 
    self = load(from_parent) 
    File "C:\Python26\lib\pickle.py", line 1370, in load 
    return Unpickler(file).load() 
    File "C:\Python26\lib\pickle.py", line 858, in load 
    dispatch[key](self) 
    File "C:\Python26\lib\pickle.py", line 1083, in load_newobj 
    obj = cls.__new__(cls, *args) 
TypeError: object.__new__(pyodbc.Cursor) is not safe, use pyodbc.Cursor.__new__() 

상황 : 나는했습니다

처리 할 데이터로 가득 찬 SQL Server 데이터베이스를 확보했습니다. 멀티 프로세싱 모듈을 사용하여 작업을 병렬화하고 내 컴퓨터의 여러 코어를 활용하려고합니다. 다음과 같이 내 일반적인 클래스 구조는 다음과 같습니다

  • MyManagerClass
    • 이 메인 클래스, 프로그램이 시작됩니다.
    • 그것은 그들이 종료 될 때까지 하나 work_queue 하나 또한 생성하고 다른 프로세스를 시작 write_queue
    • 은 다음 대기이 multiprocessing.Queue 개체를 만듭니다.
    • 참고 :이 하지 multiprocessing.managers.BaseManager의 확장()
  • MyReaderClass
    • 이 클래스는 SQL Server 데이터베이스에서 데이터를 읽고 있습니다.
    • work_queue에 항목을 넣습니다.
  • MyWorkerClass
    • 작업 처리가 일어나는 곳이다.
    • work_queue에서 항목을 가져오고 완료된 항목을 write_queue에 넣습니다.
  • MyWriterClass
    • 이 클래스는 다시 SQL Server 데이터베이스에 처리 된 데이터를 쓰는 담당하고있다.
    • write_queue에서 항목을 가져옵니다.

아이디어는 하나의 관리자, 하나의 리더, 한 작가, 많은 노동자가있을 것입니다.

기타 사항 :

나는 열려진 두 번 역 추적을 얻을, 그래서 나는이 작가에 대해 한 번 독자에 대해 한 번 발생하는 것을 생각하고있다. 내 작업자 프로세스는 잘 작성되었지만 work_queue에 아무 것도 없으므로 KeyboardInterrupt를 보낼 때까지 거기 앉아 있어야합니다.

리더와 작성자 모두 데이터베이스에 대한 자체 연결이 있으며 초기화시 작성됩니다.

솔루션 :이 솔루션을 주도 대답과 질문 마크와 페르디난트 바이어에

감사합니다. 그들은 Cursor 객체가 "pickle-able"이 아니라는 것을 정당하게 지적했다. 이것은 멀티 프로세싱이 프로세스간에 정보를 전달하는 방법이다.

내 코드의 문제점은 해당 __init__() 방법으로 데이터베이스에 연결된 MyReaderClass(multiprocessing.Process)MyWriterClass(multiprocessing.Process)입니다. MyManagerClass에 두 개체 (예 : init 메서드라고 함)를 만든 다음 start()이라고합니다.

그래서 연결 및 커서 객체를 만든 다음 피클을 통해 자식 프로세스로 전송하려고합니다. 내 솔루션은 연결 및 커서 개체의 인스턴스를 자식 프로세스가 완전히 생성 될 때까지 호출되지 않는 run() 메서드로 이동하는 것이 었습니다.

+0

그냥 말하지만 : 훌륭한 질문입니다. – mavnn

답변

8

다중 처리는 피클 링을 사용하여 프로세스간에 개체를 통신합니다. pyodbc 연결 및 커서 개체를 절대로 피클 할 수 없습니다.

>>> cPickle.dumps(aCursor) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "/usr/lib64/python2.5/copy_reg.py", line 69, in _reduce_ex 
    raise TypeError, "can't pickle %s objects" % base.__name__ 
TypeError: can't pickle Cursor objects 
>>> cPickle.dumps(dbHandle) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "/usr/lib64/python2.5/copy_reg.py", line 69, in _reduce_ex 
    raise TypeError, "can't pickle %s objects" % base.__name__ 
TypeError: can't pickle Connection objects 

, 어떤 항목 "그것은 work_queue의 항목을두고"? 커서 객체도 통과 할 수 있습니까?

+0

커서의 항목을 반복하는 생성기가 있습니다 (기본적으로 pyodbyc.Cursor(). fetchone()). 나는 그것이 큐에 넣은 튜플 (id, stuff_to_process)을 생성한다고 믿는다. deepcopy를 만들려고했으나 작동하지 않았습니다. 도움말을 살펴보면 실제로 Row 객체의 인스턴스입니다. 그래서 튜플로 변환해야 할 수도 있습니다. – tgray

+0

Row 개체는 커서 또는 뭔가에 대한 참조를 포함해야합니다. – tgray

+0

행을 튜플로 변환해도 문제가 해결되지 않았습니다. – tgray

3

pickle 모듈 내에서 오류가 발생하므로 DB-Cursor 객체가 pickle되고 unpickle (저장 장치에 직렬화되고 Python 객체로 다시 직렬화되지 않음)되는 곳에서 오류가 발생합니다.

pyodbc.Cursor은 산세를 지원하지 않습니다. 커서 객체를 계속 유지해야하는 이유는 무엇입니까?

pickle을 작업 체인의 어딘가에서 사용했는지 또는 암묵적으로 사용했는지 확인하십시오.

+0

다중 처리는 프로세스 (특히 작성한 큐 객체)간에 Pipe 객체를 암시 적으로 전달하는 데 사용됩니다. – tgray

1

pyodbc에는 Python DB-API threadsafety level 1이 있습니다. 이는 스레드가 연결을 공유 할 수 없으며 스레드 안전이 전혀 없음을 의미합니다.

기본 스레드 안전 ODBC 드라이버가 차이를 만들 것이라고 생각하지 않습니다. Python 코드에서 Pickling 오류로 표시됩니다.

관련 문제