Я хочу использовать shelve в асинхронной программе и боюсь, что каждое изменение приведет к остановке основного цикла событий.
Хотя я не возражаю против периодического замедления операции травления, запись на диск может быть существенной.
Как часто полка синхронизируется с диском? Это операция блокировки? Мне нужно вызвать .sync()
?
Если я запланирую запуск sync()
в другом потоке, другая задача asyncio может одновременно изменить полку, что нарушает требование однопоточной записи.
Он записывает на диск каждый раз, когда вы обновляете сам объект shelve
. Так что если вы это сделаете
shelf[key] = something
или
shelf.update(somedict)
он будет писать в файл.
Однако если в словаре есть изменяемые значения, их изменение не приведет к записи в файл. Объекты в Python не имеют обратной ссылки на контейнеры, которые ссылаются на них, поэтому объект полки не может обнаружить эти изменения и записать файл. Если вам необходимо поддерживать изменяемые значения в словаре, вам следует использовать опцию writeback=True
при создании полки, чтобы создать кеш в памяти; файл будет обновляться всякий раз, когда вы sync()
или close()
.
shelve
по умолчанию поддерживается модулем dbm
, который, в свою очередь, поддерживается некоторой dbm
реализацией, доступной в системе. Ни модуль shelve
, ни модуль dbm
не предпринимают никаких усилий для минимизации количества операций записи; присвоение значения ключу каждый раз вызывает запись. Даже если writeback=True
, это просто означает, что новые задания помещаются в кеш и немедленно записываются в резервную копию dbm
; они записываются, чтобы убедиться, что исходное значение существует, и запись в кэше делается, потому что назначенный объект может измениться после присвоения, и с ним нужно обращаться так же, как со только что прочитанным объектом (это означает, что он будет записан снова при sync
или close
г, на случай, если оно изменится).
Хотя возможно, что некоторые реализации базовых библиотек dbm
могут включать в себя некоторое кэширование, AFAICT, большинство из них пытаются записывать немедленно (то есть немедленно отправлять данные в ядро без буферизации в пользовательском режиме), они просто не обязательно вызывают немедленную синхронизацию диск (хотя его можно запросить, например, с помощью gdbm_sync
).
writeback=True
сделает ситуацию еще хуже, потому что когда это произойдет sync
, это потребует серьезных усилий (он буквально перезапишет каждый объект, прочитанный или записанный в БД с момента последнего sync
, потому что у него нет возможности узнать, какой из них мог быть изменен), поскольку в отличие от небольших усилий по переписыванию одной пары ключ/значение за раз.
Короче говоря, если вас действительно беспокоит блокировка записи, вы не можете использовать асинхронный код без потоков без потенциальной блокировки, но указанная блокировка, скорее всего, будет кратковременной, пока writeback=True
не задействован (или пока вы этого не сделаете sync
/close
до тех пор, пока соображения производительности не перестанут быть актуальными). Если вам нужно иметь по-настоящему неблокирующее асинхронное поведение, все взаимодействия shelve
должны происходить при блокировке в рабочих потоках, и либо writeback
должно быть False
(во избежание сбора данных в условиях гонки), либо, если writeback
есть True
, вы должны позаботиться о том, чтобы чтобы избежать изменения любого объекта, который может находиться в кеше во время sync
/close
.
Буферизация пользовательского режима была именно моим вопросом, и мне было интересно, кэширует ли какая-либо библиотека dbm эти операции. Спасибо за подробный ответ. Похоже, мне придется создать блокировку MRSW и с таким же успехом опубликовать ее с открытым исходным кодом.
В качестве примечания: модуль
shelve
не является удаленно потокобезопасным (механизм, лежащий в основеsync
, состоит в том, чтобы установитьwriteback
наFalse
, повторить все назначения, а затем снова установить его наTrue
, что означает, что все, что пишется после началаsync
, будет записано. но не кэшируется, поэтому защитаwriteback
на него не влияет), поэтому блокировка будет важна в любом многопоточном сценарии.