Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/perl/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
用perl DBI理解Segfault_Perl_Segmentation Fault_Dbi - Fatal编程技术网

用perl DBI理解Segfault

用perl DBI理解Segfault,perl,segmentation-fault,dbi,Perl,Segmentation Fault,Dbi,我有一个脚本正在执行segfault,我对解决它的方式不太满意,所以我想在这里发布这个问题,以了解更多关于它的原因,也许是更好的解决方案 以下是我的脚本所做的(删除了一些详细代码以保留其“核心”): 现在,脚本在大多数情况下运行良好。但是,当脚本的3个或更多实例并行运行时(同一个脚本,单独的进程,而不是线程),它会转到segfault 我是怎么解决的? 我通过在while(!$all_done)循环中每次执行DBH::prepare调用来解决这个问题 因此,即使多个进程并行运行,此代码也不会出错

我有一个脚本正在执行segfault,我对解决它的方式不太满意,所以我想在这里发布这个问题,以了解更多关于它的原因,也许是更好的解决方案

以下是我的脚本所做的(删除了一些详细代码以保留其“核心”):

现在,脚本在大多数情况下运行良好。但是,当脚本的3个或更多实例并行运行时(同一个脚本,单独的进程,而不是线程),它会转到segfault

我是怎么解决的? 我通过在while(!$all_done)循环中每次执行DBH::prepare调用来解决这个问题

因此,即使多个进程并行运行,此代码也不会出错。我重复了好几次错误,而且都是一致的,然后我对新代码做了同样的操作。我确信将语句移动到循环中解决了问题

你知道为什么会这样吗

我使用的是Perl5.8和PerlDBI版本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\0@\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\0@\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. ]

我想说您不需要太担心,因为SQLite语句准备往往很快。我估计通过PerlDBI编写一个简单的SQL只需20微秒(见下面的结果和代码)。考虑到您的应用程序,您不应该注意到性能上的任何差异

由于SQLite的经典锁定一次只允许一个写入程序和多个读取程序,因此您面临的问题可能与锁定或事务处理有关。然而,SIGSEGV从来都不是预期中的behvior

结果

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


在我的帖子中补充一句,以防不够清楚:只执行一次“prepare()”,然后执行多个“execute()”调用应该是正确的方法,但这样我会出错。另一方面,通过一直执行prepare()和execute(),我避免了segfault。DBH是在使用它们的线程中创建的吗?当你说“多个实例”时是脚本
fork
还是实例是独立启动的?为什么您认为底层数据库是SQLite?现在我又读了一遍这个问题,它并没有真正指出数据库是什么。我想这可能是一个猜测,或者我只是在回答之前浏览了SQLite相关的问题。
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";