扭曲线程如何避免深拷贝

6
我有一个扭曲的服务器,每个请求都会执行一些“长时间”任务,因此我推迟了每个调用的线程。在每个请求中,我访问一个共同的资源,该资源在处理过程中被修改。每个请求应该从原始数据开始,所以我在共同的资源上使用了深度复制(同时调用锁定获取)。它有效,但我认为速度不够快。我有一种感觉,深度复制会使事情变慢。
当在线程扭曲服务器中处理资源突变时,您有什么建议?

在哪些方面速度不够快?你的服务器是否无法处理每秒N个请求?有时单个请求是否需要太长时间?随着并发请求数量的增加,速度是否变慢了? - stderr
单个请求不需要太长时间。随着并发请求数量的增加,它不会变得更慢。Twisted反应器线程池大小设置为25。 - Catalin
2个回答

3

尽可能使用最少的数据在工作线程中操作。将它们需要的所有数据作为参数传递,并将它们的所有输出作为返回值(即Deferred触发的值),而不是输入的变化。

然后在反应器线程中将结果集成到公共数据结构中。

这样可以使您独立地处理工作并避免任何额外的锁定(这会导致争用,在降低速度的同时使事情更加混乱)。


你有没有一些示例/教程可以分享? - Catalin

2
如果您愿意,可以像在其他线程程序中一样使用threading.Lock来同步访问共享资源,而不是复制它。无论如何,在进行优化之前,我认为值得对代码进行基准测试,比较有和没有深度复制的性能差异,并进行其他测量以确定其性能好坏。也许它运行缓慢的原因与深度复制无关。
关于使用锁定的编辑:我的意思是您可以在此资源周围使用更细粒度的锁定。我假设您的线程不仅仅是访问共享资源。您可以尝试从多个线程执行工作并同步访问仅涉及写入共享资源的一个“关键部分”。您还可以研究使您的共享资源线程安全。例如,如果有一个共享对象SillyExampleFriendsList
class SillyExampleFriendsList(object):
    """Just manipulates a couple lists"""
    def __init__(self):
       self._lock = threading.RLock()
       self._friends = []
       self._enemies = []

    def unfriend(self, x):
       # we lock here to ensure that we're never in a state where
       # someone might think 'x' is both our friend and our enemy.
       self._lock.acquire()
       self._friends.remove(x)
       self._enemies.append(x)
       self._lock.release()

这里的重点是,通过仔细使用锁定,可以在不进行深度复制的情况下,潜在地在多个线程之间共享上述对象。但要确定所有可能需要这样做的情况并实施细粒度的锁定策略并不容易,并且这种策略可能更难以调试,同时也会引入额外的开销。
话虽如此,您可能根本不需要线程、锁或深度复制,而且如果没有对代码进行基准测试,就无法确定是否存在需要解决的性能问题。我很好奇,是什么让你觉得你的代码应该,或者需要更快?

“基准测试和优化分析至上”的观点绝对值得肯定。很多人经常会在明知某些操作较慢的情况下,仍然优化错误的部分。” - Glyph
如果我使用线程锁同步对资源的访问,那就意味着我只能使用单个线程。对此进行基准测试绝对是待办事项。 - Catalin
在CPython中,列表的单个操作是线程安全的,因此这里的“SharedList”没有任何有用的作用。 - Jean-Paul Calderone
@JP,这是个好点子。我已经更新了,试图让它更清晰明了。 - stderr
谢谢你的帮助。我们进行了一些基准测试,发现深拷贝并不是问题所在。深拷贝调用大约需要0.0009秒/次,这是微不足道的。 - Catalin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接