我正在尝试多线程同步。对于背景我有一组约100000个对象 - 可能更多 - 我想以不同的方式每秒处理多次。
现在我最关心的是同步的性能。
这是我认为应该正常工作(我省略了所有安全方面,因为这只是一个测试程序,如果出现错误,程序将崩溃..)。我写了两个funktions,第一个由程序的主线程执行,第二个由所有其他线程运行。
void SharedWorker::Start()
{
while (bRunning)
{
// Send the command to start task1
SetEvent(hTask1Event);
// Do task1 (on a subset of all objects) here
// Wait for all workers to finish task1
WaitForMultipleObjects(<NumberOfWorkers>, <ListOfTask1WorkerEvents>, TRUE, INFINITE);
// Reset the command for task1
ResetEvent(hTask1Event);
// Send the command to start task2
SetEvent(hTask2Event);
// Do task2 (on a subset of all objects) here
// Wait for all workers to finish task2
WaitForMultipleObjects(<NumberOfWorkers>, <ListOfTask2WorkerEvents>, TRUE, INFINITE);
// Reset the command for task2
ResetEvent(hTask2Event);
// Send the command to do cleanup
SetEvent(hCleanupEvent);
// Do some (on a subset of all objects) cleanup
// Wait for all workers to finish cleanup
WaitForMultipleObjects(<NumberOfWorkers>, <ListOfCleanupWorkerEvents>, TRUE, INFINITE);
// Reset the command for cleanup
ResetEvent(hCleanupEvent);
}
}
DWORD WINAPI WorkerThreads(LPVOID lpParameter)
{
while (bRunning)
{
WaitForSingleObject(hTask1Event, INFINITE);
// Unset finished cleanup
ResetEvent(hCleanedUp);
// Do task1 (on a subset of all objects) here
// Signal finished task1
SetEvent(hTask1);
WaitForSingleObject(hTask2Event, INFINITE);
// Reset task1 event
ResetEvent(hTask1);
// Do task2 (on a subset of all objects) here
// Signal finished task2
SetEvent(hTask2);
WaitForSingleObject(hCleanupEvent, INFINITE);
// Reset update event
ResetEvent(hTask2);
// Do cleanup (on a subset of all objects) here
// Signal finished cleanup
SetEvent(hCleanedUp);
}
return 0;
}
为了指出我的要求,我只想给你一个例子: 假设我们从上面获得了100000个对象,分成8个子集,每个12500个对象,一个具有8个逻辑核心的现代多核处理器。相关部分是时间。所有任务必须在大约8ms内完成。
我现在的问题是,我可以从分割处理中获得显着的时间推动,还是通过事件的同步过于昂贵?或者,如果所有任务都需要以这种方式完成,是否还有其他方式可以用更少的工作量或处理时间来同步线程?
答案 0 :(得分:0)
如果您对单个对象的处理速度很快,请不要在线程之间进行拆分。在每个上下文切换上,Windows上的线程同步将耗时超过50毫秒。系统不会使用此时间,而只是在系统上运行其他内容的时间。
但是,如果每个对象处理大约需要8毫秒,那么就可以跨线程池调度工作。但是,对象处理可能会有所不同,并且在大量计数中,工作线程将在不同时刻完成工作。
更好的方法是组织一个同步的对象队列,向其添加要处理的对象,并从中处理它们。此外,由于单个对象的处理比线程的调度间隔低得多,因此最好将它们分批处理(如10-20)。您可以估计池中的最佳工作线程数以及带有测试的批处理的最佳大小。
所以伪代码看起来像:
main_thread:
init queue
start workers
set counter to 100000
add 100000 objects to queue
while (counter) wait();
worker_thread:
while (!done)
get up to 10 objects from queue
process objects
counter -= processed count
if (counter == 0) notify done