我需要执行1000次昂贵的功能。执行可能需要5秒到10分钟。因此它具有很大的变化。 我喜欢有多个线程在上面工作。我目前的实现是在250次调用中设计了这1000次调用,并产生了4个线程。但是,如果一个线程有一个"糟糕的一天",与其他3个线程相比,它的完成时间要长得多。
因此,每当线程完成上一次调用时,我都希望对该函数进行新的调用 - 直到完成所有1000次调用。
我认为线程池可以工作 - 但是如果可能的话,我希望有一个简单的方法(=尽可能减少额外的代码)。基于任务的设计也朝这个方向发展(我认为)。对此有一个简单的解决方案吗?
答案 0 :(得分:2)
初始化1000个单位的信号量。让4个线程中的每一个都绕着信号量wait()和工作函数循环。
然后,所有线程将对该函数起作用,直到它被执行了1000次。即使其中三个线程卡住并且需要很长时间,第四个线程也会处理其他997个呼叫。
[编辑] 嗯..一般来说,标准的C ++ 11库不包含信号量。但是,信号量是一个基本的OS sunchro原语,所以应该很容易调用,例如。与POSIX。
答案 1 :(得分:0)
鉴于您已经能够将调用分段为单独的实体和要处理的线程。一旦方法是使用std::package_task
(及其关联的std::future
)来处理函数调用,并将它们放在某种队列中。反过来,每个线程都可以获取打包的任务并进行处理。
你需要锁定队列以进行并发访问,这里可能存在一些瓶颈,但与线程可能会有一个糟糕的日子相关的问题相比,这应该是最小的。这实际上是一个线程池,但它允许您控制任务的执行。
另一个替代方法是使用std::async
并指定其launch policy as std::launch::async
,缺点是您不能控制线程创建本身,因此您依赖于标准库控制线程vs的效率你有多少核心。
任何一种方法都可行,关键是在合理的样本量上测量方法的性能。措施应该是时间和资源使用(线程和保持核心繁忙)。大多数操作系统将包括测量过程资源使用情况的方法。
答案 2 :(得分:0)
您可以使用Exectuors的任一参考实现,然后通过
调用该函数#include <experimental/thread_pool>
using std::experimental::post;
using std::experimental::thread_pool;
thread_pool pool_{1};
void do_big_task()
{
for (auto i : n)
{
post(pool_, [=]
{
// do your work here;
});
}
}
执行者正在使用C ++ 17,所以我想我会早点进入。
或者,如果您想尝试另一种执行程序,那么more recent implementation的语法略有不同。