2012-04-07 262 views
0

我有一段腳本正在執行段錯誤,而且我解決這個問題的方式並不舒服,因此我想在此處發佈問題以更多地瞭解它的原因,並且也許更好的解決方案。使用perl-DBI瞭解Segfault

這裏是我的腳本做什麼(刪除了一些詳細的代碼離開「核心」的話):

# Here's a query I need to do every X seconds to monitor progress of other tasks 
# This is apparently the key to my segfault problem 
my $stmt = $dbh->prepare($query); 

my $all_done = 0; 
while(!$all_done) { 
    $self->debug("Waiting for $n blocker tasks to be finished"); 

    # Execute query to pull the status of the tasks from DB 
    $stmt->execute(); 

    my $pending = []; 
    while(my $hr = $stmt->fetchrow_hashref()) { 
     push @{$pending}, $hr->{'TASK_NAME'} if ($hr->{'STATUS'} ne 'COMPLETE'); 
    } 

    if(scalar(@{$pending}) > 0) { 
     $all_done = 0; 
     sleep($sleep_gap); 
    } 
    else { $all_done = 1; } 
} 

現在,腳本運行良好,大部分時間。但是,當腳本的3個或更多實例並行運行(相同的腳本,單獨的進程,而不是線程)時,它會進入段錯誤。

我是如何解決它的? 我通過在while(!$ all_done)循環中每次執行DBH :: prepare調用來解決它。

因此,即使有多個進程並行運行,此代碼也不會發生段錯誤。我一再重複了這個錯誤,然後對新代碼做了同樣的處理。我肯定的是,在循環內移動語句修復了這個問題。

任何想法,爲什麼會發生這種情況?

我使用的是perl 5.8和perl-DBI版本1.609。

這裏也是strace的時候輸出腳本段錯誤:

read(5, "\1\7\0\0\6\0\0\0\0\0\20\27\234\312\272\221eG2;\33S\364\230\313\220\221Bxp\4\7"..., 2064) = 263 
write(4, "\1\31\0\0\6\0\0\0\0\0\21i \1\1\0\0\0\2\0\0\0\3^!)\4\4\0\0\0\0"..., 281) = 281 
read(4, "\0\177\0\0\6\0\0\0\0\0\v\5\2\0\0\0\1\0\0\0\0\0\0\0\0\0\0\0 \10\6"..., 2064) = 127 
write(2, "debug:Waiting for 1 blocker task"..., 49debug:Waiting for 1 blocker tasks to be finished 
) = 49 
write(5, "\0\252\0\0\6\0\0\0\0\0\3^\20p\200\0\0\2\0\0\0\0\0\0\0\0\1\r\0\0\0\0"..., 170) = 170 
read(5, "\0\301\0\0\6\0\0\0\0\0\6\"\2\0\0\[email protected]\0\0\0\0\0\0\0\0\0\0\0\7 ru"..., 2064) = 193 
write(5, "\1]\0\0\6\0\0\0\0\0\3^\21)\200\0\0\0\0\0\0\1\234\0\0\0\1\r\0\0\0\0"..., 349) = 349 
read(5, "\0y\0\0\6\0\0\0\0\0\10\6\0S\254b\f\0\t\0\0\1\0\0\0\1\0\0\0\0\0\0"..., 2064) = 121 
write(5, "\0000\0\0\6\0\0\0\0\0\3h\22\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 48) = 48 
read(5, "\0\26\0\0\6\0\0\0\0\0\10\2\0\0\0\t\5\0\0\0\21\0", 2064) = 22 
time(NULL)        = 1333827285 
rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0 
rt_sigaction(SIGCHLD, NULL, {SIG_DFL}, 8) = 0 
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0 
nanosleep({10, 0}, {10, 0})    = 0 
time(NULL)        = 1333827295 
write(4, "\1\31\0\0\6\0\0\0\0\0\21i\"\1\1\0\0\0\3\0\0\0\3^#)\4\4\0\0\0\0"..., 281) = 281 
read(4, "\0\177\0\0\6\0\0\0\0\0\v\5\2\0\0\0\1\0\0\0\0\0\0\0\0\0\0\0 \10\6"..., 2064) = 127 
write(2, "debug:Waiting for 1 blocker task"..., 49debug:Waiting for 1 blocker tasks to be finished 
) = 49 
write(5, "\0)\0\0\6\0\0\0\0\0\21i\23\1\1\0\0\0\1\0\0\0\3N\24\2\0\0\[email protected]\0\0"..., 41) = 41 
read(5, "\1>\0\0\6\0\0\0\0\0\20\27\234\312\272\221eG2;\33S\364\230\313\220\221Bxp\4\7"..., 2064) = 318 
--- SIGSEGV (Segmentation fault) @ 0 (0) --- 
+++ killed by SIGSEGV +++ 
[ Process PID=22767 runs in 32 bit mode. ] 
+0

只需添加到我的帖子,在情況下,它是不夠清楚:做「準備()」只有一次,然後多個「執行( )「調用應該是正確的方式來做到這一點,但這樣我就會發生段錯誤。另一方面,通過一直執行prepare()和execute()來避免段錯誤。 – juansaba 2012-04-07 20:41:20

+0

是否在使用它們的線程中創建了DBH? – ikegami 2012-04-07 20:49:04

+0

當你說「多個實例」做了'fork'腳本還是實例獨立啓動? – cjm 2012-04-08 00:08:19

回答

1

我說你沒有太多的擔心,因爲SQLite的聲明準備往往要快。我確信通過Perl DBI進行簡單的SQL準備只需要20微秒(請參閱下面的結果和代碼)。考慮到您的應用程序,您不應該注意到任何性能差異。

由於SQLite的經典鎖定一次只允許一個寫入器和多個讀取器,因此您面臨的問題可能與鎖定或事務處理有關。但是SIGSEGV從來不是預期的行爲。

結果

Perl 5.014002 
DBI 1.618 
SQLite 3.7.9 
time in s for 100000 prepares: 2.01810789108276 
ys per prepare: 20.1810789108276 

代碼

use DBI; 
use Time::HiRes qw (time); 
use strict; 
use warnings; 

my $dbc = DBI->connect (
'dbi:SQLite:dbname=/tmp/test.db', 
    undef, undef, { AutoCommit => 0, RaiseError => 1, PrintError => 1 } 
) || die $DBI::errstr; 

print "Perl $]\n"; 
print "DBI $DBI::VERSION\n"; 
print "SQLite $dbc->{sqlite_version}\n"; 

my $start = time(); 

my $n = 100_000; 

foreach (1 .. $n) { 

my $stmt = $dbc->prepare(qq{ 
    select count(*) from sec where sid is not null 
}); 

} 

my $end = time(); 

print 
"time in s for $n prepares: " . 
($end - $start) . 
"\n"; 

print 
"ys per prepare: " . 
((($end - $start) * 1_000_000)/$n) . 
"\n"; 
+0

你爲什麼認爲底層數據庫是SQLite? – mob 2012-04-09 15:38:06

+0

現在我已經讀過這個問題了,它並沒有真正指出數據庫是什麼。我假設它可能是猜測,或者我可能在回答之前就是在瀏覽與SQLite相關的問題。 – XDF 2012-04-17 15:43:22