任意睡眠在线程等待超时

Bac*_*ach 10 python sleep python-multithreading python-2.7

在我开始描述我的问题之前,值得一提的是我正在使用Python 2.7.我没有检查过,但这可能与Python 3.x无关.

在使用Python的队列时,我发现了一些奇怪的东西.通常,当从队列中获取对象时,我允许长但有限的超时(例如几秒),以便在没有找到对象的情况下允许调试和错误报告.我发现的是,有时在将对象插入先前空的队列的时间与get同一个队列的方法返回该对象的时间之间存在奇怪的差距,即使该方法在该对象之前被调用put被称为该对象.

挖了一点我发现睡眠填补了这个空白.在Queue模块中,如果timeout正被传递给自变量get的方法没有None,并且是肯定的,则non_empty Conditionwait方法被称为具有正参数(即不是100%精确的;事实上,所述Queue的' _qsize’方法,该方法返回底层的长度deque首先被验证为返回0,但只要队列在第一个位置为空,接下来就是条件的等待.

Conditionswait方法的行为不同,如果它得到超时或不.如果它没有得到任何超时,它只是调用waiter.acquire.这是在C我理解的范围内定义的,但它似乎正常.然而,如果超时给予,出现睡的离奇序列相反,当睡眠时间在一些任意大小(1个milisecond)开始,并随着时间的推移变得更长.这是运行的确切代码:

# Balancing act:  We can't afford a pure busy loop, so we
# have to sleep; but if we sleep the whole timeout time,
# we'll be unresponsive.  The scheme here sleeps very
# little at first, longer as time goes on, but never longer
# than 20 times per second (or the timeout time remaining).
endtime = _time() + timeout
delay = 0.0005 # 500 us -> initial delay of 1 ms
while True:
    gotit = waiter.acquire(0)
    if gotit:
        break
    remaining = endtime - _time()
    if remaining <= 0:
        break
    delay = min(delay * 2, remaining, .05)
    _sleep(delay)
Run Code Online (Sandbox Code Playgroud)

这显然是我在新对象放入先前空的队列之间发现的差距以及已经调用的get方法返回该对象的时间之间的差距的原因.随着延迟时间呈指数级增长直到被一个巨大的(从我的角度来看)大小0.05秒所阻挡,它会在我的应用程序的生命中产生令人惊讶和不必要的重要睡眠.

你能解释一下这个目的是什么吗?Python开发人员是否认为没有Python用户会关心这样的时间长度?有快速的解决方法或正确的解决方案吗?你建议我过载螺纹模块吗?

shx*_*hx2 5

我最近遇到了同样的问题,我也跟踪到了threading模块中这个确切的代码块.

太糟糕了.


你能解释一下这个目的是什么吗?Python开发人员是否认为没有Python用户会关心这样的时间长度?

甘拜下风...


你建议我过载螺纹模块吗?

要么重载线程模块,要么迁移到python3已修复此部分实现的位置.

在我的情况下,迁移到python3本来是一项巨大的努力,所以我选择了前者.我做的是:

  1. 我创建了一个带有接口的快速.so文件(使用cython)pthread.它包括调用相应pthread_mutex_*函数的python函数和链接libpthread.具体来说,与我们感兴趣的任务最相关的功能是pthread_mutex_timedlock.
  2. 我创建了一个新threading2模块,(并替换import threading了我的代码库中的所有行import threading2).在threading2我从重新定义的所有相关的类threading(Lock,Condition,Event),并从那些Queue我用了很多(QueuePriorityQueue).该Lock级完全使用重新实现pthread_mutex_*的功能,但其余的要容易得多-我只是子类原(如threading.Event),并重写__init__创建我的新Lock类型.其余的只是工作.

新的实施Lock类型非常相似,在原执行threading,但根据我的新的实行acquire上的代码,我发现在python3threading模块(这自然是比上述'平衡行为’块简单得多).这部分相当容易.

(顺便说一下,我的结果是我的大规模多线程进程加速了30%.甚至超出了我的预期.)

我希望这有帮助.