Kam*_*duk 3 perl multithreading thread-synchronization
我有[az,AZ] ASCII数字的数组,如下所示: my @alphabet = (65..90,97..122);
所以主线程功能是从字母表中检查每个字符,如果条件为真则返回字符串.
简单的例子:
my @output = ();
for my $ascii(@alphabet){
thread->new(\sub{ return chr($ascii); });
}
Run Code Online (Sandbox Code Playgroud)
我想在每个ASCII号上运行线程,然后以正确的顺序将线程函数中的字母放入数组中.
因此,在out case中,数组@output应该是动态的,并且[a..z,A-Z]在所有线程完成其工作后包含.
如何检查,是否已完成所有线程并保持订单?
你正在寻找$thread->join,等待线程完成.它的记录在这里,和这太问题也可能会有所帮助.
因为在你的情况下,看起来在线程中完成的工作在成本上大致相等(没有线程比任何其他线程花费更长的时间),你可以join按顺序将每个线程按顺序等待它们全部完成:
# Store all the threads for each letter in an array.
my @threads = map { thread->new(\sub{ return chr($_); }) } @alphabet;
my @results = map { $_->join } @threads;
Run Code Online (Sandbox Code Playgroud)
因为,当第一个线程返回时join,其他线程可能已经完成并且只是等待"加入"以获取它们的返回代码,或者即将完成,这使得您非常接近"尽可能快"的并行性,并且,由于线程是按顺序创建的,@results因此已经免费订购.
现在,如果您的线程可以花费不同的时间来完成,或者您需要在将"子线程"结果插入输出数据结构之前在"主"/生成线程中执行一些耗时的处理,那么join它们可能会按顺序执行不太好.在这种情况下,您需要以某种方式:a)检测线程"退出"事件,或者b)轮询以查看哪些线程已退出.
您可以使用从子线程发送到主/生成线程的信号/通知来检测线程"退出"事件.最简单/最常用的方法是使用cond_wait和cond_signal函数threads::shared.您的主线程将等待来自子线程的信号,处理它们的输出,并将其存储到结果数组中.如果采用这种方法,则应该将结果数组预先分配到正确的大小,并为线程提供输出索引(例如,for在创建线程时使用C风格的循环并让它们返回($result, $index_to_store)或类似),这样您就可以存储结果在正确的地方即使他们出了故障.
你可以使用is_joinable线程实例方法轮询完成哪些线程,或者使用循环中的threads->list(threads::joinable)和threads->list(threads::running)方法(希望不是忙碌的等待;添加一个睡眠调用 - 甚至是一个亚秒来自Time::HiRes- 将节省很多性能/在这种情况下电池)检测事情何时完成并获取结果.
重要的警告:产卵线程的数量庞大的执行大量并行工作的,尤其是如果工作是小/快速完成,可能导致性能问题,它可能是更好的使用线程的数量较少,每做多而不是一件"工作"(例如,产生少量线程,并且每个线程使用threads::shared函数来锁定并弹出"工作要做"的共享数组中的第一个项目而不是将工作映射到线程作为1:1).1:1映射会产生两个主要的性能问题:
return看看).如果您需要做的工作很快,那么大量线程的线程管理开销会比仅管理一些可重用的线程慢得多.如果最终得到的线程比逻辑CPU核心多得多,并且每个线程正在进行CPU密集型工作,或者每个线程正在访问相同的资源(例如,从相同的磁盘或数据库中的相同行读取),你很快就遇到了表演悬崖.调整线程的"资源"下面的数字(这些是否为CPU或硬盘驱动器或诸如此类的东西)往往会产生更好的吞吐量不是信任线程调度器更多的线程比有上运行它们的可用资源之间进行切换.这个原因很慢的原因非常广泛:
因为线程调度程序(操作系统的一部分,而不是语言)无法充分了解每个线程正在尝试做什么,所以在给定知识有限的情况下,抢占式调度不能优化某个点的性能.
TL; DR线程不会在一定时间内提高性能,在此之后它们会使性能变差.如果可以,重用与可用资源相对应的多个线程; 不要创建/销毁与需要完成的任务相对应的单个线程.