最近我一直在研究各种线程池架构。 "经典"线程池架构通常有N个线程和一个共享任务队列。我认为只要个别任务足够大,这种架构就可以充分扩展。但是对于执行许多小任务的线程池,单个队列可能成为瓶颈。
我通过我的研究发现的唯一一个解决这个问题的架构是"work-stealing" architecture。而不是单个共享任务队列,有1"私有"每个线程的任务队列。每个工作线程在其自己的专用队列上执行任务,然后当它没有更多任务时,它开始随机选择其他队列并且"窃取"他们的任务。因此,只要存在更多任务,这就可以确保所有线程始终可以完成工作,并且还可以解决单队列瓶颈问题。
然而,似乎从未提及的一个问题是这样的工作窃取队列如何能够保证所有CPU线程将始终以与单个共享队列保证相同的方式使用。问题在于,在某些时候,当没有更多的工作要做时,线程池必须 sleep - 即它必须等待信号量或条件变量,直到更多的工作到达。否则,即使没有任何队列入队,线程池也会无休止地消耗CPU周期。但是如果一个工作窃取线程池必须要睡眠,可能需要一个与每个队列关联的信号量/条件变量 - 否则,如果它使用了共享信号量,我们就会回到单个共享的同一瓶颈问题队列 - 即,每个生产者线程都需要与共享信号量/条件var的信令竞争。所以这表明一个工作窃取线程池应该每个队列有一个sempahore / condition-variable。
但如果是这样的话,那么似乎并不能保证线程池能够保证所有CPU都能得到有效利用。例如,假设我们有8个线程和8个队列。所有线程都处于休眠状态,但线程[0]除外,它正忙于执行任务。现在,生产者线程运气不好,并在队列[0]上排队另一个任务。使用共享队列,新任务将立即由空闲线程执行。但是由于工作窃取池,其他7个线程只会闲置,因为他们从未被告知新任务,也无法知道还有更多工作要做。
这让我相信"偷工作"线程池在高工作负载下可以很好地扩展,但是在低或中等水平下#34;工作负载,它永远不能保证所有线程实际上都被充分利用。
那么在解决线程池工作的设计方面如何解决这个问题呢?