【问题标题】:Twisted threading howto avoid deepcopyTwisted threading 如何避免深拷贝
【发布时间】:2011-10-28 08:18:06
【问题描述】:

我有一个扭曲的服务器,它为每个请求执行一些“长”任务,所以我推迟每个调用的线程。在每个请求中,我访问一个公共资源,该资源在此过程中会被更改。每个请求都应该从原始数据开始,所以我在公共资源上使用 deepcopy(同时调用锁获取)。它有效,但我认为它不够快。我觉得 deepcopy 有点慢。

在处理具有资源突变的线程扭曲服务器时,您有什么建议?

【问题讨论】:

  • 速度不够快的原因是什么?您的服务器是否无法每秒处理 N 个请求?单个请求有时会花费太长时间吗?随着并发请求数量的增加,它会变慢吗?
  • 单个请求不会花费太长时间。随着我增加并发请求的数量,它并没有变慢。 Twisted reactor 线程池大小设置为 25。

标签: python multithreading twisted deep-copy


【解决方案1】:

如果您愿意,您可以像在任何其他线程程序中一样,将共享资源的访问与threading.Lock 同步,而不是复制它。

无论如何,我认为值得在使用和不使用 deepcopy 的情况下对您的代码进行基准测试,并在进行优化之前进行测量以确定性能的好坏程度。也许它慢的原因与 deepcopy 无关。

关于使用锁定的编辑:我的意思是您可以围绕此资源使用更细粒度的锁定。我假设您的线程所做的不仅仅是访问共享资源。您可以尝试从多个线程工作中受益,然后将访问同步到仅涉及写入共享资源的一个“关键部分”。您还可以调查使您的共享资源线程安全。例如,如果有一个共享对象,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()

这里的重点是,上述对象可能会在多个线程之间共享,而无需通过仔细使用锁进行深度复制。识别所有可能需要这样做的情况并非易事,细粒度锁定策略可能更难以调试并且仍然会引入开销。

也就是说,您可能根本不需要线程、锁或 deepcopy,而且如果不对代码进行基准测试,就不清楚您是否有需要解决的性能问题。我很好奇是什么让您认为您的代码应该或需要更快?

【讨论】:

  • 对于“基准和个人资料第一”的情绪肯定 +1。人们经常优化错误的东西,即使他们知道某些东西实际上很慢。
  • 如果我用线程同步对资源的访问。锁意味着我去单线程。对事物进行基准测试肯定是在 TODO 上。
  • 列表上的单个操作在 CPython 中是线程安全的,所以这里的 SharedList 没有任何用处。
  • @JP,这很好。我已更新以使其更清晰。
  • 感谢您的帮助。我们做了一些基准测试,发现 deepcopy 不是问题。深度复制调用大约需要:0.0009 秒/调用,这是微不足道的。
【解决方案2】:

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

然后将结果整合到reactor线程中的通用数据结构中。

这使您可以独立地推理工作并避免任何额外的锁定(这会导致争用、减慢速度以及使它们更加混乱)。

【讨论】:

  • 你有什么例子/教程要分享吗?
猜你喜欢
  • 1970-01-01
  • 2014-12-17
  • 2012-04-12
  • 2015-01-13
  • 2011-09-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多