Несколько потоков Python, обращающихся к одному файлу
У меня есть два потока, один из которых записывается в файл, а другой - периодически
перемещает файл в другое место. Запись всегда вызывает open
перед записью сообщения и вызывает close
после записи сообщения. Для выполнения перемещения движок использует shutil.move.
Я вижу, что после того, как первый шаг сделан, писатель больше не может писать в файл, т.е. размер файла всегда равен 0 после первого перемещения. Я что-то делаю неправильно?
Ответы
Ответ 1
Блокировка - это возможное решение, но я предпочитаю общую архитектуру наличия каждого внешнего ресурса (включая файл), который обрабатывается одним отдельным потоком. Другие потоки отправляют рабочие запросы в выделенный поток на экземпляр Queue.Queue (и предоставляют отдельную отдельную очередь в качестве части параметров запроса на работу если они нуждаются в возврате результата), выделенный поток тратит большую часть своего времени на .get
в этой очереди, и всякий раз, когда он получает запросы, выполняется и выполняет его (и при необходимости возвращает результаты в очередь передачи).
Я привел подробные примеры этого подхода, например. в "Python в двух словах". Очередь Python по своей сути является потокобезопасной и чрезвычайно упрощает вашу жизнь.
Среди преимуществ этой архитектуры заключается в том, что она плавно переходит на multiprocessing, если и когда вы решите переключить некоторую работу на отдельный процесс вместо отдельного потока (например, для использования нескольких ядер) - multiprocessing
предоставляет свой собственный рабочий тип Queue
, чтобы сделать такой переход гладким, как шелк; -).
Ответ 2
Когда два потока обращаются к тем же ресурсам, происходят странные вещи. Чтобы этого избежать, всегда блокируйте ресурс. Для этого у Python есть удобный threading.Lock
, а также некоторые другие инструменты (см. Документацию модуля threading
).
Ответ 3
Отъезд http://www.evanfosmark.com/2009/01/cross-platform-file-locking-support-in-python/
Вы можете использовать простую блокировку с его кодом, как написано Эван Фосмарк в более старом вопросе StackOverflow:
from filelock import FileLock
with FileLock("myfile.txt"):
# work with the file as it is now locked
print("Lock acquired.")
Одна из самых элегантных библиотек, которые я когда-либо видел.