这个问题是一个好奇心点,作为下面两个程序之一工作。Perl线程中的垃圾回收
我使用Image :: Magick调整大小的照片。为了节省一点时间,我在每个照片的自己的线程中工作,并使用信号量来限制同时工作的线程数。本来我允许每个线程一次运行,但脚本会快速为所有照片分配3.5 GB(我只有2GB可用),并且由于所有交换到磁盘,脚本运行速度比正常情况慢5倍。
工作,信号灯版本的代码看起来是这样的:
use threads;
use Thread::Semaphore;
use Image::Magick;
my $s = Thread::Semaphore->new(4);
foreach (@photos) {
threads->create(\&launch_thread, $s);
}
foreach my $thr (reverse threads->list()) {
$thr->join();
}
sub launch_thread {
my $s = shift;
$s->down();
my $image = Image::Magick->new();
# do memory-heavy work here
$s->up();
}
这很快分配500MB,并很好地运行,而无需以往需要更多。 (线程是加入了相反的顺序提出一个观点。)
我想知道是否有可能与同时发动80个线程,并阻止他们大多是架空的,所以我改变了我的脚本来阻塞主线程:
my $s = Thread::Semaphore->new(4);
foreach (@photos) {
$s->down();
threads->create(\&launch_thread, $s);
}
foreach my $thr (threads->list()) {
$thr->join();
}
sub launch_thread {
my $s = shift;
my $image = Image::Magick->new();
# do memory-heavy work here
$s->up();
}
该版本开始正常,但逐渐积累了原始版本使用的3.5GB空间。它比一次运行所有线程更快,但仍然比阻塞线程慢很多。
我的第一个猜测是线程所使用的内存在调用join()之前不会被释放,并且因为它是阻塞的主线程,所以在分配全部线程之前不会释放线程。但是,在第一个工作版本中,线程按照或多或少的随机顺序传递守卫,但以相反的顺序连接。如果我的猜测是正确的,那么比任何时候四个正在运行的线程都要等待join(),这个版本也应该更慢一些。
那么为什么这两个版本如此不同呢?
接下来我要尝试排队。我只是好奇Perl中发生了什么,使信号量的一个版本完美工作,而且一个工作非常糟糕。 – pconley
在您的版本中,只有解锁sem的线程才会使用大量内存。如果您在完成时收获它们,那意味着在任何给定时间只有4个线程正在使用大量内存。如果你最终只收获它们,80个线程最终会占用大量内存。 – ikegami