Пределы многопоточных вкладок в sqlite - PullRequest
4 голосов
/ 11 июля 2011

мой Perl-скрипт является многопоточным, и в каждом потоке мне нужно что-то записать в базу данных sqlite3. Но, как вы можете догадаться, я получаю много

Ошибка DBD :: SQLite :: db: база данных заблокирована в строке script.pl 264.

сообщения. Я читал, что sqlite3 способен обрабатывать многопоточные ситуации, даже операторы INSERT, но я думаю, что многого ожидаю, вставляя одновременно 8 потоков.

хорошо, так что это невозможно, но нет возможности выполнить проверку перед вставкой, чтобы увидеть, заблокирована ли база данных (или занята), а затем подождать, пока она снова не освободится?

Я действительно не хочу переходить на "настоящую" СУБД, потому что это всего лишь простой скрипт.

Спасибо

Ответы [ 3 ]

6 голосов
/ 11 июля 2011

Если вам нужно заблокировать, пока вы не попадете в базу данных, попробуйте эксклюзивные транзакции, т.е.

$dbh->do("begin exclusive transaction") or die $dbh->errstr;
#inserts here
$dbh->do("commit transaction") or die $dbh->errstr;

Таким образом, вы делегируете блокировку SQLite, а не делаете это в Perl. Это безопаснее по разным причинам, не в последнюю очередь из-за того, что база данных может быть открыта в чем-то отличном от Perl или в другом процессе Perl, а не в потоке.

И, как прокомментировал @mob, многопоточность Perl - довольно забавный зверь. Я бы просто сделал блокировку базой данных, которой она принадлежит.

2 голосов
/ 12 июля 2011

При записи в базу данных SQLite блокирует весь файл базы данных с помощью fcntl ().Когда другой процесс / поток пытается записать в него, он будет ждать установленное количество времени (30 секунд?), А затем сдается.См. SQLiteFAQ .

Обратите внимание, что хотя потоки Perl действительно глючные и странные, это не принципиальная проблема.Я пришел к выводу, что SQLite - неподходящий выбор для всех, кроме самых простых нужд.

1 голос
/ 11 июля 2011

Одной из альтернатив может быть вставка каждого потока в свою собственную промежуточную таблицу, затем использование lock для переменной (фиктивная переменная подходит) и вставка в финальную таблицу, пока поток имеет блокировку. Другими словами, что-то вроде ...

sub ThreadStuff
{
    my $tid=threads->tid;
    #Thread is doing whatever it's doing
    $dbh->do("delete from staging_" . $tid) or die $dbh->errstr;
    $dbh->do("insert into staging_" . $tid . "stuff;") or die $dbh->errstr;

    {
        lock $hall_pass;
        $dbh->do("insert into final_table select * from staging_" . $tid) or die $dbh->errstr;
        #The lock on $hall_pass goes away as soon as we leave this block.
    }
    #Other stuff, maybe cleanup or whatever.
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...