0

我有归结为一个函数:设计模式,而循环

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

我怎么能改写这个高效异步执行,假设所有的功能都是线程安全的,独立于以前的迭代,并且可能需要比最大允许线程数多的迭代次数?

这里的问题是我们不知道需要提前多少次迭代,所以我们不能使用dispatch_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--; 
} 

回答

1

根据您的描述,它看起来像generateConfigurationForTesting是某种随机化技术或以其他方式产生的,它可以使配置的接近无限数量的(因此您的评论,你不知道的时候怎么提前许多迭代你将需要)。以此为假设,你基本上被你创建的模型所困,因为你的执行者需要受到关于队列的一些合理假设的限制,并且你不想过度生成,因为这只会扩展在您成功找到value ==good测量值之后的运行时间长度。

我建议你考虑使用队列(或OSAtomicIncrement*OSAtomicDecrement*)保护接thread_countdoWork。按照现状,thread_count递增和递减将发生在两个不同的队列中(主线程的main_queue和后台任务的缺省队列),因此可以同时递增和递减线程数。这可能会导致计数不足(这会导致创建比您期望的更多的线程)或超额计数(这会导致您永远无法完成您的任务)。

如果value!=goodcheckResult,则将checkResult添加到队列中,让其看起来更好一点的另一种方法是将checkResult添加到队列中。这样,您使用dispatch_apply(20, queue, ^{ ... })加载队列的初始元素,而根本不需要thread_count。前20个将使用dispatch_apply(或dispatch_apply认为适合您的配置的数量)添加,然后每次调用checkResult时,您都可以设置doWork=false或将另一个操作添加到queue

+0

是的,我正在实施一种随机搜索算法;但它也可能是一种遗传优化的框架。 – koan 2013-05-14 19:52:04

1

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

+0

什么是ncpu?假设ncpu是一些大数字;你的解决方案可以让GCD同时运行多个线程,因为系统可以处理并且每个线程都像循环一样运行。找到解决方案后,使用'doWork'完成每个线程,然后'dispatch_apply()'中的所有线程都会用完。是对的吗 ? – koan 2013-05-14 19:50:35

+1

抱歉不清楚,ncpu是系统中的cpus的数量,例如,从'sysctlbyname(“hw.ncpu”,...)'。是的,通过这种方法'dispatch_apply()'基本上被用作一种有效的方式来让所有的cpus重复运行你的问题,直到找到解决方案。 – das 2013-05-14 20:05:27