Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/364.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 中断队列。获取_Python_Python 3.x - Fatal编程技术网

Python 中断队列。获取

Python 中断队列。获取,python,python-3.x,Python,Python 3.x,如何在Python3.X中中断阻塞队列.get() 在Python2.X中似乎可以工作,但在Python3.5中却不能这样说 运行在Windows7、CPython3.5.1、64位机器和Python上。 看起来它在Ubuntu上的表现不一样。它在Python 2上工作的原因是队列。在Python 2上带超时的get实现得非常糟糕;Python2实际上没有一个支持定时阻塞获取的锁原语(这是队列内部条件变量需要的,但是缺少,因此它使用繁忙循环)。当您在Python2上尝试这一点时,您要检查的是Ct

如何在Python3.X中中断阻塞
队列.get()

在Python2.X中似乎可以工作,但在Python3.5中却不能这样说

运行在Windows7、CPython3.5.1、64位机器和Python上。
看起来它在Ubuntu上的表现不一样。

它在Python 2上工作的原因是
队列。在Python 2上带超时的get
实现得非常糟糕;Python2实际上没有一个支持定时阻塞获取的锁原语(这是
队列
内部
条件
变量需要的,但是缺少,因此它使用繁忙循环)。当您在Python2上尝试这一点时,您要检查的是
Ctrl-C
是否在一个(短的)
时间后被处理。sleep
调用完成,并且,它非常短,即使在新的睡眠开始时按Ctrl-C,您可能也不会注意到

Python3提供了真正的定时锁获取支持(这要归功于将目标操作系统的数量缩小到那些具有本机定时互斥或某种信号量的操作系统)。因此,您实际上在整个超时期间阻塞锁获取,而不是在轮询尝试之间阻塞0.05秒

看起来Windows允许注册Ctrl-C的处理程序,这意味着不会中断锁获取来处理它。当定时锁获取最终失败时,Python会被告知
Ctrl-C
,因此如果超时很短,您最终会看到
键盘中断
,但直到超时结束后才会看到它。由于Python2
Condition
一次只休眠0.05秒(或更少),因此Ctrl-C总是被快速处理,但Python3将一直休眠,直到获得锁为止

Ctrl-Break
保证作为一个信号,但Python也不能正确处理它(它只是终止进程),这可能不是您想要的

如果希望
Ctrl-C
工作,您在某种程度上会被困在轮询中,但至少(与Python 2不同)您可以有效地轮询
Ctrl-C
,同时在剩余时间对队列进行实时阻塞(因此,您会收到一个项目立即变为空闲的警报,这是常见情况)

导入时间
导入队列
def get_timed_可中断(q,超时):
stoploop=time.monotonic()+超时-1
而time.monotonic()
这会一次阻塞一秒钟,直到:

  • 剩余时间不到一秒钟(它会阻塞剩余时间,然后允许
    正常传播)
  • Ctrl-C
    在一秒钟的时间间隔内被按下(在该秒钟的剩余时间过后,
    KeyboardInterrupt
    被触发)
  • 获取一个项目(如果按下
    Ctrl-C
    ,它也将在此时升起)

  • 正如上面提供的伟大答案@ShadowRanger的评论线程中提到的,这里是他的函数的另一种简化形式:

    import queue
    
    
    def get_timed_interruptable(in_queue, timeout):
        '''                                                                         
        Perform a queue.get() with a short timeout to avoid                         
        blocking SIGINT on Windows.                                                 
        '''
        while True:
            try:
                # Allow check for Ctrl-C every second                               
                return in_queue.get(timeout=min(1, timeout))
            except queue.Empty:
                if timeout < 1:
                    raise
                else:
                    timeout -= 1
    

    只需使用不会阻塞的
    get\u nowait

    导入时间
    ...
    尽管如此:
    如果不是q.empty():
    q、 获取_nowait()
    打破
    时间。睡眠(1)#可选超时
    

    这显然是在忙着等待,但是
    q.get()
    基本上做了相同的事情。

    Dunno,这就是为什么我要问这个问题,它在Python 3中工作,例如,
    python3-c“导入队列;queue.queue().get()”
    在我的Ubuntu机器上被
    Ctrl+c
    成功中断。你确定你使用的是python3可执行文件,而不是python2吗?在我的windows上
    Ctrl+C
    不会中断它应该不会
    Ctrl+Break
    在windows上工作?@ChrisP
    Ctrl+Break
    Ctrl+C
    不同。请参阅两个注意事项-首先,
    队列上的1秒超时。get()
    调用将对用户产生明显的延迟,我建议使用更短的时间。第二,保持
    stoptime
    remaining
    违反-只需使用
    while time.monotonic()
    和remaine
    remaining
    @SteveCohen:我已调整以消除附加变量(并减少每循环算法);我不能直接使用
    time.monotonic()
    ,因为我希望循环在剩下不到一秒钟时停止。至于延误;嗯。一秒钟的延迟取消节目几乎没有意义;如果Ctrl-C要取消一个任务,但要继续运行,并且必须有响应,那么可以调整超时时间,但我正在针对常见情况进行优化;通常情况下,Ctrl-C很少(成本从未支付),阻塞是半常见的(更多的循环会增加常见情况的成本)。当然,如果超时时间小于1,您仍然会遇到这样的问题:
    queue.get()
    。这真的很糟糕,因为
    队列.get()
    应该至少发生一次。如果使用更短的超时,可以忽略(微不足道的)溢出情况并简化整个过程。正如您在回复中提到的,Python 2在0.05秒(ish)时进行了轮询。@SteveCohen:它在最后的
    get
    中执行(尽管我必须修正计算以确保它在竞争条件下不会低于0,
    Queue.get
    不会像我想象的那样将<0的超时视为0),即使在运行不到一秒的情况下,只有循环中忽略
    queue.Empty
    的循环才会被跳过。0.05秒的轮询循环太短;我在工作项目中遇到过一些问题,这些问题假设生产者-消费者链中的许多线程(每个线程为下一个线程提供数据)可以使用定时阻塞等待,但最终的结果是Py2中的大量GIL争用;他们会使用1.4-1.8个核,做0.6-0.8个核的工作
    import queue
    
    
    def get_timed_interruptable(in_queue, timeout):
        '''                                                                         
        Perform a queue.get() with a short timeout to avoid                         
        blocking SIGINT on Windows.                                                 
        '''
        while True:
            try:
                # Allow check for Ctrl-C every second                               
                return in_queue.get(timeout=min(1, timeout))
            except queue.Empty:
                if timeout < 1:
                    raise
                else:
                    timeout -= 1
    
    import time
    import queue
    
    
    def get_timed_interruptable_precise(in_queue, timeout):
        '''                                                                         
        Perform a queue.get() with a short timeout to avoid                         
        blocking SIGINT on Windows.  Track the time closely
        for high precision on the timeout.                                                 
        '''
        timeout += time.monotonic()
        while True:
            try:
                # Allow check for Ctrl-C every second                               
                return in_queue.get(timeout=max(0, min(1, timeout - time.monotonic())))
            except queue.Empty:
                if time.monotonic() > timeout:
                    raise