0

我有一个功能可以归结为:

while(doWork)
{
  config = generateConfigurationForTesting();
  result = executeWork(config);
  doWork = isDone(result);
}

假设所有函数都是线程安全的,独立于先前的迭代,并且可能需要比允许的最大线程数更多的迭代,我该如何重写它以实现高效的异步执行?

这里的问题是我们不知道提前需要多少次迭代,所以我们不能制作 adispatch_group或使用dispatch_apply.

这是我的第一次尝试,但由于任意选择的值和睡眠对我来说看起来有点难看;

int thread_count = 0;
bool doWork = true;
int max_threads = 20;  // arbitrarily chosen number

dispatch_queue_t queue =
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

while(doWork)
{
  if(thread_count < max_threads)
  {
    dispatch_async(queue, ^{ Config myconfig = generateConfigurationForTesting();
                             Result myresult = executeWork();
                             dispatch_async(queue, checkResult(myresult)); });
    thread_count++;
  }
  else
    usleep(100); // don't consume too much CPU
}

void checkResult(Result value)
{
  if(value == good) doWork = false;
  thread_count--;
}
4

2 回答 2

1

根据您的描述,它看起来像是generateConfigurationForTesting某种随机化技术或其他可以进行近乎无限数量的配置的生成器(因此您的评论是您不提前知道需要多少次迭代)。以此为假设,您基本上坚持使用您创建的模型,因为您的执行程序需要受到有关队列的一些合理假设的限制,并且您不想过度生成,因为这只会扩展成功找到value ==good测量值后运行的长度。

我建议您考虑使用队列(或OSAtomicIncrement*and OSAtomicDecrement*)来保护对thread_countand的访问doWork。就目前而言,thread_count递增和递减将发生在两个不同的队列中(主线程的 main_queue 和后台任务的默认队列),因此可以同时递增和递减线程计数。这可能导致计数不足(这将导致创建的线程比您预期的更多)或计数过多(这将导致您永远无法完成任务)。

使这个看起来更好一点的另一个选择是checkResult在队列中添加新元素 if value!=good。这样,您可以使用加载队列的初始元素,dispatch_apply( 20, queue, ^{ ... })而您根本不需要thread_count。前 20 个将使用dispatch_apply(或dispatch_apply感觉适合您的配置的数量)添加,然后每次checkResult调用您都可以设置doWork=false或添加另一个操作到queue.

于 2013-05-14T11:40:52.707 回答
1

dispatch_apply()为此,只需将 ncpu 作为迭代次数传递(应用从不使用超过 ncpu 工作线程),并保持工作块的每个实例运行,只要有更多工作要做(即循环回到generateConfigurationForTesting()除非!doWork)。

于 2013-05-14T17:57:55.700 回答