我有1000-10000个职位的名单。它存储在简单的char数组中。我需要尽快完成清单上的工作。
我想随时运行10个线程。如何在完成上一个线程之后立即(或几乎立即)运行新线程?
#define THREADS_LIMIT 10
const char * const jobs[]= { "data1", .... }
...
for (i = 0; i < THREADS_LIMIT; ++i)
{
// run first 10 threads
}
如何在上一次完成后启动线程?我可以运行10个线程,然后等待所有的线程完成,然后运行下一个10.但是有更有效的方法吗?
答案 0 :(得分:5)
不要停止任何线程。只需让每个线程移动到下一个工作,而不是销毁它并创建一个新工作;当没有更多工作时,它们会终止。现在你的主程序只是启动THREAD_LIMIT线程,然后pthread_join
全部启动。
答案 1 :(得分:1)
您可能会考虑的一件事是拥有一个线程安全的作业队列,每个线程可以从中拉出工作,直到没有剩余工作为止。然后启动但是许多线程是合适的,让它们全部工作,直到没有更多的工作。类似的东西:
#define THREADS_LIMIT 10
static pthread_mutex_t job_mutex = PTHREAD_MUTEX_INITIALIZER;
static const char * const jobs[]= { "data1", .... };
char const* get_job(void)
{
pthread_mutex_lock( &job_mutex);
static char const* next_job = jobs;
static char const* jobs_end = jobs + (sizeof(jobs)/sizeof(jobs[0]));
char const* result = NULL;
if (next_job != jobs_end) {
result = next_job++;
}
pthread_mutex_unlock( &job_mutex);
return result;
}
...
for (i = 0; i < THREADS_LIMIT; ++i)
{
// run first 10 threads
}
void* thread_fun( void* arg)
{
for (char const* my_job = get_job(); my_job != NULL; my_job = get_job()) {
// work on the job *my_job
}
return 0;
}
请注意,如果您的作业是CPU密集型的,那么您应该将它们的数量限制为机器所具有的CPU核心数。不止于此,他们将互相争夺CPU时间。
但是,如果您希望灵活地使作业队列动态化(因此可以在线程正在工作时将作业添加到队列中),则复杂性会增加。它只是增长一点,以保持添加/删除逻辑线程安全。但是为了确保仍然存在处理作业队列的线程,它会增长很多 - 例如,你必须确保没有竞争条件你认为还有一个或多个线程来处理队列,但这些线程实际上即将结束自己而不再检查作业队列。 当然,在成本上存储作业的方式会更加复杂,您可以对其进行扩展,以便作业队列可以添加项目
答案 2 :(得分:0)
您肯定需要一个线程池,您不希望为每个任务启动和停止线程。
主要的设计问题是如何将任务分发到池中,这些问题可以通过像0mq这样的中间件包简化,以便在调度程序和工作程序之间执行无锁IPC。
如果作业列表是硬编码的,那么您可以静态地分割工作负载,并说给每个线程一个索引进入作业队列并让它们迭代直到完成。
答案 3 :(得分:0)
最好的方法(在我看来)是创建一个包含作业的队列,然后启动十个线程,这些线程只是从队列中读取下一个作业并进行处理。
这具有最小的线程创建/销毁开销以及线程之间的工作负载自动平衡的优点。通过这种方式,我的意思是获得快速工作的线程会自动获得更多工作。
然后,在这10,000个作业结束时,放置10个关闭作业,这将导致工作线程退出,然后等待它们。
整个计划如下:
main thread:
create a queue
do ten times:
start a worker thread
do ten thousand times:
add normal job to queue
do ten times:
add shutdown job to queue
wait for all workers to finish
exit
worker thread:
while true:
get job from queue
if job is shutdown job:
exit
process job
显然,需要使用互斥锁来保护对队列的访问,以避免竞争条件。
你需要记住一件事。如果任务是CPU密集型的,那么拥有比可用执行单元(CPU或内核或其他任何东西)更多的线程,您将无法获得任何实际好处。
例如,如果您只有一个核心,那么最快的方法就是根本不使用线程。在这样的CPU密集型任务中使用线程实际上可能更慢,因为你引入了任务切换的开销。