我们假设我们有一个打开文件的脚本,然后逐行读取并将该行打印到终端。我们有一个sigle线程和一个多线程版本。
问题在于两个脚本的结果输出几乎相同,但不完全是。在多线程版本中,大约有十行错过了前两个字符。我的意思是,如果真正的线条是" Stackoverflow摇滚",我获得" ackoverflow rocks"。
我认为这与一些竞争条件有关,因为如果我调整参数来创造很多小工人,我会得到更多的错误,而不是如果我使用更少和更大的工人。
单线程是这样的:
$file = "some/file.txt";
open (INPUT, $file) or die "Error: $!\n";
while ($line = <STDIN>) {
print $line;
}
多线程版本使用线程队列,此实现基于@ikegami方法:
use threads qw( async );
use Thread::Queue 3.01 qw( );
use constant NUM_WORKERS => 4;
use constant WORK_UNIT_SIZE => 100000;
sub worker {
my ($job) = @_;
for (@$job) {
print $_;
}
}
my $q = Thread::Queue->new();
async { while (defined( my $job = $q->dequeue() )) { worker($job); } }
for 1..NUM_WORKERS;
my $done = 0;
while (!$done) {
my @lines;
while (@lines < WORK_UNIT_SIZE) {
my $line = <>;
if (!defined($line)) {
$done = 1;
last;
}
push @lines, $line;
}
$q->enqueue(\@lines) if @lines;
}
$q->end();
$_->join for threads->list;
答案 0 :(得分:4)
我尝试了你的程序,得到了类似的(错误的)结果。 Thread::Semaphore
使用lock
print
而不是use threads;
use threads::shared;
...
my $mtx : shared;
sub worker
{
my ($job) = @_;
for (@$job) {
lock($mtx); # (b)locks
print $_;
# autom. unlocked here
}
}
...
,而不是$mtx
,因为它比T :: S更简单,例如:
undef
全局变量lock
充当互斥锁。它的价值并不重要,即使lock
(就像这里)也可以。
对for
的调用会阻止并仅在其他线程当前没有锁定该变量时返回。
当它超出范围时,它会自动解锁(从而使{…}
返回)。在此示例中发生
在print
循环的每次迭代之后;没有额外的print
阻止。
现在我们已同步use threads;
use threads::shared;
...
my $mtx : shared;
$| = 1; # force unbuffered output
sub worker
{
# as above
}
...
次来电话......
但是这也没有用,因为lock
确实缓冲了I / O(好吧,只有O)。所以我强制无缓冲输出:
Sub CheckSpecialCharacters()
'This macro looks for any characters above 255 and tags them with the appropriate existing language character.
Dim ch As Range: Set ch = ActiveDocument.Characters(1)
Do
Counter = Counter + 1
ch.Select
myValue = AscW(Selection.Text)
If myValue > 255 Then
If (myValue > 8190 And myValue < 8225) Or (myValue > 288 And myValue < 381) Or (myValue > 701 And myValue < 704) Or myValue = 730 Then
'Ignores Curly Quotes and Transliteration punctuation
ElseIf (myValue > 7935 And myValue < 8192) Or (myValue > 879 And myValue < 1024) Then
'Greek Characters get langgrk applied
Selection.Expand unit:=wdWord
Selection.Style = "langgrk"
ElseIf (myValue > 1423 And myValue < 1535) Then
'Hebrew Characters get langheb applied
Selection.Expand unit:=wdWord
Selection.Style = "langheb"
ElseIf myValue > 7679 And myValue < 7830 Then
'Extended transliteration characters get langtrans applied //OLD VALUES// (myValue > 288 And myValue < 381) Or (myValue > 701 And myValue < 704)
If HCCP = True Then Selection.Expand unit:=wdWord
Selection.Style = "langtrans"
ElseIf (myValue > 19968 And myValue < 40959) Then
'Chinese Characters get langchin applied
Selection.Expand unit:=wdWord
Selection.Style = "langchin"
ElseIf (myValue > 19968 And myValue < 40917) Then
'Japanese Characters get langjap applied
Selection.Expand unit:=wdWord
Selection.Style = "langjap"
Else
If HCCP = True Then Selection.Expand unit:=wdWord
Selection.Style = "lang"
End If
End If
DoNext:
End Sub
然后它奏效了。令我惊讶的是,我可以移除!==
,它仍然有效。也许是偶然的。请注意,如果没有缓冲,您的脚本运行速度会明显变慢。
我的结论是:你是threads::shared
。