我对perl比较陌生,甚至对perl中的线程也比较陌生。我有一个perl脚本,可以从3个不同的来源获取输入。(2个LDAP查询和一个并不总是存在的文件),因为某些部分可能比其他部分耗时更长,所以我决定使用线程和队列。在开发期间,测试脚本的各个组件工作得很好,但在将它们放在一起之后,性能似乎会下降。
基本结构是这两个线程:(读取文件或读取AD条目) -> Queue1 -> 2线程:(擦除数据) -> Queue2 -> 3-4个线程(与现有本地LDAP条目进行比较)。几个线程将统计数据报告回主脚本,一旦所有线程完成,就会发送一封电子邮件,其中包含该运行的所有统计数据和状态。
我正在使用dequeue_nb,我认为这会有帮助,但没有运气。
性能影响似乎出现在队列中。在寻找提高性能的技巧时,我遇到了几篇文章,说perl线程不好,并使用coro、POE、Anyevent、IO:async等。
这看起来不像是一个“事件”问题,所以我不认为AnyEvent或POE会是我所看到的那样,coros似乎一次只使用一个CPU,所以我也不确定这是否会起作用。我想使用它们的组合,但后来我的头开始痛。有没有人对如何修复/解决我的脚本或如何实现其他模块有任何建议?
发布于 2012-07-31 04:17:32
并行性的一个问题是同步。它是一个性能杀手,它是不好的,如果可能的话,它应该被避免。
运维架构
让我们来看看你的架构:
+--------------+--------------+
| Input 1 | Input 2 |
+--------------+--------------+
| QUEUE A |
+--------------+--------------+
| Scrub 1 | Scrub 2 |
+--------------+--------------+
| QUEUE B |
+---------+---------+---------+
| Compare | Compare | Compare |
+---------+---------+---------+讨论
队列A必须跨四个线程进行同步;队列B跨5-6个线程。任何时候只有一个线程可以访问队列,所以大多数时候你的线程都是在等待,而不是在工作!
并行流水线架构
稍有不同的体系结构可能如下所示:
+-----------+ +-----------+
| Input 1 | | Input 2 |
+-----------+ +-----------+
| QUEUE 1A | | QUEUE 2A |
+-----------+ +-----------+
| Scrub 1 | | Scrub 2 |
+-----------+ +-----------+
| QUEUE 1B | | QUEUE 2B |
+-----+-----+ +-----+-----+
| Cmp | Cmp | | Cmp | Cmp |
+-----+-----+ +-----+-----+讨论
在这里,A队列只有两个线程(->less等待),B队列只有三个线程。对于相似的输入大小/复杂性,这种架构应该执行得更快。如果输入2相当短,整个流水线2甚至在流水线1完成一半之前就已经运行了。然而,这比对每个管道使用单个进程要好得多。
草坪喷水建筑
概念
更好的架构将尝试将进程的输出分布到多个队列中。(相反,当队列为空时,让线程从多个队列获取输入是不好的。)
每次队列写入都应该转到不同的队列:
+-----------+ +-----------+
| Input 1 | | Input 2 |
+-----------+ +-----------+
| \ / |
+-----------+ +-----------+
| QUEUE 1A | | QUEUE 2A |
+-----------+ +-----------+
| Scrub 1 | | Scrub 2 |
+-----------+ +-----------+
/ | \ \ / / | \
+-------+-------+-------+-------+
| Q. 1B | Q. 2B | Q. 3B | Q. 4B |
+-------+-------+-------+-------+
| Cmp | Cmp | Cmp | Cmp |
+-------+-------+-------+-------+这可确保每个线程具有相同的工作负载,但不能确保所有线程同时完成。
讨论
所有队列在3个线程之间共享。问题是两个线程在写入队列时会互相阻塞。如果队列写访问之间的时间明显长于写持续时间,这应该是没有问题的,否则第二种体系结构可以混合使用。
因此,这种架构是否有意义取决于您的确切需求。
对于均匀大小的输入,它的速度较慢,但对于不规则的输入,它的性能更好。
附录
在实现时:
所使用的框架是架构的次要部分。如果只传递文本字符串,我强烈建议使用管道。如果您必须传递Perl数据类型或对象,那么您可能不得不接受使用真实队列的额外开销:在向队列添加非共享变量时,除了所有同步开销之外,还必须进行深度复制(请参阅@Leon Timmermans )。
关于可伸缩性:
架构1和架构3的线程数量不是固定的。我强烈建议使用这种灵活性来对不同的组成进行基准测试。经验法则是,您应该使用n到2n个线程,其中n是处理器(或硬件线程)的数量。这可以看作是一个阶段的线程的最大可感知数量。除此之外,你只会得到内存损失,而不会加速。当阶段处理输入的速度比提供输入的速度更快时,性能饱和点可能会更早达到。
发布于 2012-07-31 05:51:07
您要在队列中放入哪种类型的数据?AFAIK简单数据比复杂结构更便宜,因为它需要克隆和复制至少两次。我一直在计划写一个更快的队列实现(大部分工作实际上已经完成了),但还没有发布。
https://stackoverflow.com/questions/11727655
复制相似问题