我正在研究.NET(TPL)的任务并行库,我试图理解它是如何工作的,我理解工作窃取的想法,但我无法理解为什么我们使用重复队列以及它是如何工作的?
创建新任务时,谁指定应该接受哪个线程并将其放入任务队列?
你可以帮帮我吗?答案 0 :(得分:4)
想象一下,您自己正在实施TPL并使用普通的非重复工作窃取队列。因此,对于每个队列,您有一个线程可以从队列的尾部推送和弹出,以及多个线程可以从队列的头部获取(在本文中称为小偷)。因为您要确保添加到队列中的每个任务都完全删除(通过弹出或通过获取),您必须在三个操作中的每个操作中使用锁定。
在某种程度上,当你知道只有一个线程要使用这些操作时,锁定push和pop似乎很浪费。但如果您想确保队列行为正确,那么您无能为力。
你的图书馆有效,但你意识到经常发生的是你正在等待一项甚至尚未开始的任务。那么,在当前线程中同步运行它呢?你可以这样做,但问题是任务在某个队列中,你不能安全快速地从那里删除它。你可以做的是为任务添加一个标志,指示其状态,并以线程安全的方式访问该标志。
这样,如果您最终将任务出列,则不会运行它,因为您知道它已在运行甚至已完成。队列怎么样?我们说过要确保从队列中删除任务一次。但这不再是必需的:如果我们删除一些任务两次,那没关系,因为任务本身会处理它并且实际上只启动一次。
但这意味着我们可以从pop和push中删除锁,从而产生重复队列,这比正常的工作窃取队列更快,因为它的要求较弱:我们可以确保从中删除每个任务< em>至少一次。
编辑:对问题的反应:
删除任务是可以的,但是通过推送队列中的任务来删除任务!
抱歉,这是一个错误,现在已修复。它突然出现了。
第6页的fib示例中的案例3,是吗?
是
为什么呢?我无法理解这个问题。
问题是,这个任务可能在任何线程的队列中,或者它当前可以在任何线程上执行。因此,您必须至少搜索每个线程上运行的任务,并为每个线程使用锁定。每当线程改变其运行任务时,每个线程都必须使用锁。如果任务当前未在运行,则必须至少锁定要从中删除的队列。这也使得对队列行为的分析更加复杂:现在事情可以从队列中间消失。
从pop和push中移除锁定以及复制队列之间的逻辑链接是什么?
删除锁定后,您无法完全确定任务被删除一次。可能发生的是队列中只有一个任务,两个不同的线程同时调用take和pop。因为pop不使用锁,所以同一任务被删除两次。