python程序可以创建的锁数有限制吗?

时间:2016-06-02 23:18:18

标签: python multithreading

我有一个单线程python3程序,我试图转换为使用多个线程。我有一个类似于树的数据结构,可以读取和写入。可能有许多线程需要同时读写。

关于这一点的一个显而易见的方法是对整个数据结构使用单个锁:在写入发生时没有人可以读取,一次只能发生一次写入,并且当有待处理时不会发生写入读取。

但是,我希望锁定更精细,以获得更好的性能。它是一棵完整的16棵树,当人口密集时,它有大约5到6百万片叶子(实际上大部分都是平衡的,但不能保证)。如果我想要最细粒度的锁定,我可以锁定叶子的父母。这意味着超过10万把锁。

我必须承认,我还没试过这个。但我想我先问一下:是否存在任何硬件限制或性能原因导致我无法创建如此多的锁定对象?也就是说,我是否应该考虑从根(例如,256锁)锁定到深度2?

感谢您的任何见解。

修改

更多详情:

我还不知道有多少内核,因为我们仍然在试验我们需要多少计算能力,但我猜测只有极少数核心将被使用。

我的目标是大约50,000个线程。有异步I / O,每个插槽一个线程。在代码的引导阶段,尽可能多的线程将同时运行(受硬件限制),但这是一次性成本。我们更感兴趣的是一旦事情开始运行。在这一点上,我冒险猜测每秒只有几千个正在运行。我需要测量响应时间,但我猜它每个唤醒周期大约10ms。这是一次活动的几十个线程(平均而言)。

现在我写出来了,也许这就是我的问题的答案。如果我一次只需要几十个线程读取或写入,那么我就不需要在树上进行细粒度锁定。

2 个答案:

答案 0 :(得分:2)

过早优化

这是过早优化的典型例子。在不知道线程花费多少时间阻塞的情况下,可能等待其他写入发生,不清楚从创建管理数千个锁的额外复杂性中你必须获得什么。

全球口译员锁

线程本身可能是一个不成熟的优化。你的任务是否易于线程化?许多线程可以安全地并行工作吗?需要大量共享状态(即许多频繁锁定)的任务通常是高线程计数的不良候选者。在python中,由于GIL,你可能会看到更少的好处。您的线程是否正在执行大量IO,或者调用外部应用程序,或者使用用C编写的python模块来正确释放GIL?如果没有,线程可能实际上不会给你带来任何好处。您可以使用multiprocessing模块来回避GIL,但是跨越流程边界传递锁定和写入会产生开销,具有讽刺意味的是,它可能会使您的应用程序变得更慢

队列

另一种选择是使用写入队列。如果线程实际上不需要共享状态,但它们都需要写入同一个对象(即从该对象读取的次数很少),您可以简单地将写入添加到队列并让一个线程处理写入,不需要任何锁。

答案 1 :(得分:1)

回应Brendan Abel:避免过早优化。如果我有16个内核,则不能超过16个并行访问(读/写)。没有任何东西可以悬挂kajillion锁。有限数量的锁就足够了。那么问题就变成:如果我对一组资源进行随机访问,那么两个内核将同时尝试访问同一资源的可能性是多少?

例如,如果我有16个核心试图随机访问16个资源,那么一个阻止另一个核心的可能性很高。也就是说,16个对象的排列很少,而16个对象的16个独立选择:16个! vs 16 ^ 16。 阻止的可能性大约是百万分之一。 (注意:我之前在问题下面的评论是关闭的。)另一方面,如果我有16个内核随机访问256个资源,阻塞的几率下降到大约38%。当你获得16个核心和4096个资源时,阻塞的可能性低于3%。

这与birthday paradox

有关

注意:我在这里假设一个线程阻止另一个线程是不可取的,等待是不可接受的。但是,如上所述,要做的就是衡量。不要花费更多的工程努力来优化那些不需要的东西。