2014-11-10 5 views
1

(Пожалуйста, обратите внимание: Существует вопрос называется «SQLite3 и многопроцессорные», но этот вопрос на самом деле о многопоточности и так принято отвечать, это не duplicate)многопроцессном SQLite ВСТАВИТЬ: «база данных заблокирована»

Я реализую многопроцессорный скрипт, каждый процесс должен будет написать некоторые результаты в таблице sqlite. Моя программа продолжает сбой с database is locked (с sqlite допускается только одна модификация БД).

Вот пример того, что у меня есть:

def scan(n): 
    n = n + 1 # Some calculation 

    cur.execute("      \ 
        INSERT INTO hello \ 
        (n)    \ 
        VALUES ('"+n+"') \ 
       ") 

    con.commit() 
    con.close() 

    return True 


if __name__ == '__main__': 

    pool = Pool(processes=int(sys.argv[1])) 

    for status in pool.imap_unordered(scan, range(0,9999)): 
     if status: 
      print "ok" 

    pool.close() 

Я попытался с помощью замка, объявив замок в основной и использовать его как глобальный scan(), но это не мешало мне получать database is locked.

Каков правильный способ убедиться, что только один оператор INSERT будет выпущен одновременно в многопроцессорном скрипте Python?

EDIT:

Я бегу на Debian на базе Linux.

+0

Какая у вас операционная система? SQLite поддерживает консультативную/региональную блокировку для конкуренции между конкурирующими авторами, поэтому, хотя одна запись может происходить одновременно, в соответствующей операционной системе с соответствующей конфигурацией, это просто приводит к медленному/блокированию для других авторов, а не к этому , –

+0

Это подробно обсуждается в http://www.sqlite.org/lockingv3.html. В этом отношении - в частности, какая версия SQLite? Если это pre-3.0 (чего не должно быть - это уже более десяти лет), то у вас нет этой функции. –

+1

На совершенно другом примечании, между прочим, НЕ ВСЕГДА используйте конкатенацию строк для создания ваших SQL-запросов. Таким образом, Bobby Tables ... –

ответ

3

Это произойдет, если блокировка записи не может быть захвачена (по умолчанию) 5-секундным таймаутом. В общем, убедитесь, что ваш код COMMIT выполняет свои транзакции с достаточной частотой, тем самым освобождая блокировку и позволяя другим процессам иметь возможность ее захватить. Если вы хотите подождать дольше, вы можете сделать это:

db = sqlite.connect(filename, timeout=30.0) 

... ждет 30 секунд.

+0

Отлично! Если у меня есть несколько INSERT, я должен освободить блокировку между ними? Или выпускать каждый подряд, а затем совершать? – Juicy

+3

В идеале, для достижения эффективности вы хотите найти разумную среднюю позицию с точки зрения размера партии. Слишком короткий, и вы занимаете больше времени в целом, слишком велики, и ваши отдельные транзакции занимают слишком много времени (и удерживайте блокировку в течение длительного периода). Конечно, иногда проблема корректности будет определять размер партии сильнее, чем производительность. –