Проблема:Python многопроцессорность и доступ к базе данных с 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
- Это основной класс, где начинается программа.
- Это создает два объекта multiprocessing.Queue, один
work_queue
и одинwrite_queue
- Он также создает и запускает другие процессы, то их ждет, чтобы закончить.
- Примечание: это не расширение multiprocessing.managers.BaseManager()
- MyReaderClass
- Этот класс считывает данные из базы данных SQL Server.
- Он ставит предметы в
work_queue
.
- MyWorkerClass
- Это где обработка происходит работа.
- Он получает предметы от
work_queue
и ставит готовые предметы вwrite_queue
.
- MyWriterClass
- Этот класс отвечает за написание обработанных данных обратно в базу данных SQL Server.
- Он получает предметы от
write_queue
.
Идея заключается в том, что там будет один менеджер, один читатель, один писатель, и многие рабочие.
Другие детали:
Я получаю отслеживающий дважды в STDERR, так что я думаю, что это происходит один раз для читателя и один раз для писателя. Мои рабочие процессы создаются отлично, но просто сидите там, пока я не отправлю KeyboardInterrupt, потому что у них ничего нет в work_queue
.
У читателя и писателя есть собственное подключение к базе данных, созданной при инициализации.
Решение:
Благодаря Марку и Фердинанд Бейер за их ответы и вопросы, которые привели к этому решению. Они по праву отметили, что объект Cursor не «pickle-able», который является методом, который многопроцессор использует для передачи информации между процессами.
Проблема с моим кодом заключалась в том, что MyReaderClass(multiprocessing.Process)
и MyWriterClass(multiprocessing.Process)
оба подключены к базе данных в своих методах __init__()
. Я создал оба этих объекта (т. Е. Их метод init) в MyManagerClass
, а затем вызвал start()
.
Таким образом, это создаст объекты соединения и курсора, а затем попытается отправить их дочернему процессу через рассол. Мое решение состояло в том, чтобы перенести экземпляр объекта соединения и курсора на метод run(), который не вызывается до тех пор, пока дочерний процесс не будет полностью создан.
Просто сказать: отличный вопрос. – mavnn