- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我正在学习python的threading模块,写了下面的代码帮助自己理解
from Queue import Queue
import threading
lock = threading.Lock()
MAX_THREADS = 8
q = Queue()
count = 0
# some i/o process
def io_process(x):
pass
# process that deals with shared resources
def shared_resource_process(x):
pass
def func():
global q, count
while not q.empty():
x = q.get()
io_process(x)
if lock.acquire():
shared_resource_process(x)
print '%s is processing %r' %(threading.currentThread().getName(), x)
count += 1
lock.release()
def main():
global q
for i in range(40):
q.put(i)
threads = []
for i in range(MAX_THREADS):
threads.append(threading.Thread(target=func))
for t in threads:
t.start()
for t in threads:
t.join()
print 'multi-thread done.'
print count == 40
if __name__ == '__main__':
main()
输出像这样卡住了:
Thread-1 is processing 32
Thread-8 is processing 33
Thread-6 is processing 34
Thread-2 is processing 35
Thread-5 is processing 36
Thread-3 is processing 37
Thread-7 is processing 38
Thread-4 is processing 39
请注意 main() 中的打印未执行,这意味着某些线程挂起/阻塞?
然后我通过添加 q.task_done() 修改 func() 方法:
if lock.acquire():
shared_resource_process(x)
print '%s is processing %r' %(threading.currentThread().getName(), x)
count += 1
q.task_done() # why is this necessary ?
lock.release()
现在所有线程都如我所料终止并得到正确的输出:
Thread-6 is processing 36
Thread-4 is processing 37
Thread-3 is processing 38
Thread-7 is processing 39
multi-thread done.
True
Process finished with exit code 0
我阅读了 Queue.Queue 的文档 here并查看 task_done() 与 queue.join() 一起使用以确保处理队列中的所有项目。但是因为我没有在 main() 中调用 queue.join(),为什么 task_done() 在 func() 中是必需的?当我错过 task_done() 代码时,线程挂起/阻塞的原因是什么?
最佳答案
您的代码中存在竞争条件。想象一下,您在 Queue
中只剩下一个项目,并且您将只使用两个线程而不是 8 个。然后会发生以下事件序列:
q.empty
检查它是否为空。由于队列中有一项结果为False
,因此执行了循环体。q.get
之前有一个上下文切换,线程 B 开始运行。q.empty
,队列中还有一项,结果为False
,执行循环体。q.get
没有参数,它会立即返回队列中的最后一项。然后线程 B 处理项目并退出,因为 q.empty
返回 True
。q.empty
,所以接下来会调用 q.get
,但这将永远阻塞,因此您的程序不会终止。您可以通过导入 time
并稍微更改循环来模拟上述行为:
while not q.empty():
time.sleep(0.1) # Force context switch
x = q.get()
请注意,无论是否调用 task_done
,行为都是相同的。
那么为什么添加 task_done
有帮助?默认情况下,Python 2 将每 100 条解释器指令进行一次上下文切换,因此添加代码可能会改变上下文切换发生的位置。参见 another question和 linked PDF为了更好的解释。在我的机器上,无论 task_done
是否存在,程序都不会挂起,所以这只是一个推测,是什么导致了你发生这种情况。
如果你想修复这个行为,你可以有无限循环并将参数传递给 get
指示它不要阻塞。这会导致 get
最终抛出 Queue.Empty
异常,您可以捕获该异常然后中断循环:
from Queue import Queue, Empty
def func():
global q, count
while True:
try:
x = q.get(False)
except Empty:
break
io_process(x)
if lock.acquire():
shared_resource_process(x)
print '%s is processing %r' %(threading.currentThread().getName(), x)
count += 1
lock.release()
关于python - 为什么这里需要 Queue.join() ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42558797/
我试图弄清楚以下模块正在做什么。 import Queue import multiprocessing import threading class BufferedReadQueue(Queue.
如果我使用 Queue.Queue,那么我的 read() 函数不起作用,为什么?但是,如果我使用 multiprocessing.Queue,它运行良好: from multiprocessing
我正在寻找比我在文档中找到的更多关于 Python 队列实现的见解。 根据我的理解,如果我在这方面有误,请原谅我的无知: queue.Queue():通过内存中的基本数组实现,因此不能在多个进程之间共
当我使用多处理模块(Windows 上的 Python 2.7)中的队列代替 Queue.Queue 时,我的程序没有完全关闭。 最终,我想使用 multiprocessing.Process 处理
阅读了大量的 JavaScript 事件循环教程,我看到了不同的术语来标识队列存储消息,当调用堆栈为空时,事件循环准备好获取消息: 队列 消息队列 事件队列 我找不到规范的术语来识别它。 甚至 MDN
我收到错误消息“类型队列不接受参数”。当我将更改队列行替换为 PriorityQueue 时,此错误消失并且编译正常。有什么区别以及如何将其更改为编译队列和常规队列? import java.util
如何将项目返回到 queue.Queue?如果任务失败,这在线程或多处理中很有用,这样任务就不会丢失。 docs for queue.Queue.get()说函数可以“从队列中删除并返回一个项目”,但
如何在多个 queue.Queue 上进行“选择”同时? Golang 有 desired feature及其 channel : select { case i1 = 声明。 线程:queue 模
http://docs.python.org/2/library/queue.html#Queue.Queue.put 这似乎是一个幼稚的问题,但我在文档和谷歌搜索中都没有找到答案,那么这些方法是线程
这可能是个愚蠢的问题,但我对与 .dequeue() 和 $.queue() 一起使用的 .queue() 感到困惑> 或 jquery.queue()。 它们是否相同,如果是,为什么 jquery
我正在尝试创建一个线程化的 tcp 流处理程序类线程和主线程对话,但是 Queue.Queue 也没有做我需要的,服务器从另一个程序接收数据,我只想传递它进入主线程进行处理这里是我到目前为止的代码:
The principal challenge of multi-threaded applications is coordinating threads that share data or ot
在Queue模块的queue类中,有几个方法,分别是qsize、empty 和 full,其文档声称它们“不可靠”。 他们到底有什么不可靠的地方? 我确实注意到 on the Python docs网
我需要一个队列,多个线程可以将内容放入其中,并且多个线程可以从中读取。 Python 至少有两个队列类,Queue.Queue 和 collections.deque,前者似乎在内部使用后者。两者都在
明天我将介绍我选择进程内消息队列实现的基本原理,但我无法阐明我的推理。我的合作设计者提议我们实现一个简单的异步队列,只使用基本的作业列表和互斥锁来控制访问,我建议在嵌入式模式下使用 ActiveMQ。
在 scala 中定义了一个特征: trait Queue[T] Queue 是一种类型吗?或其他东西,例如类型构造函数? 来自 http://artima.com/pins1ed/type-para
我看到 SML/NJ 包含一个队列结构。我不知道如何使用它。如何使用 SML/NJ 提供的附加库? 最佳答案 Queue structure SML '97 未指定,但它存在于 SML/NJ 的顶级环
我是 D3 和 JavaScript 的新手。 我试图理解其中的 queue.js。 我已经完成了 this关联。但是仍然无法清楚地了解 queue.await() 和 queue.awaitAll(
所以我试图在我的 main.cpp 文件中调用一个函数,但我得到“错误:没有匹配函数来调用‘Queue::Queue()。” 队列.h #ifndef QUEUE_H #define QUEUE_H
假设我有一个 10 行的二维 numpy 数组 例如 array([[ 23425. , 521331.40625], [ 23465. , 521246.03125],
我是一名优秀的程序员,十分优秀!