GCD性能差 [英] GCD Poor Performance

查看:165
本文介绍了GCD性能差的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

你可能还记得,我试图使用GCD来加速我的一些代码,即碰撞检测和解析引擎。但是,我明显做错了,因为我的所有GCD代码是显着更慢,不如我的序列代码(在1.4倍和10倍慢)之间的一致性。让我给你一个例子:我以一个冒泡排序方式迭代数组,以确定数组中对象之间的所有可能的碰撞:

As you may remember, I am trying to use GCD to speed up some of my code, namely a collision detection and resolution engine. However, I am clearly doing something wrong because all of my GCD code is significantly slower and less consistent than my serial code (between 1.4x and 10x slower). Allow me to give you an example: I am iterating over an array in a bubble-sort fashion to determine all possible collisions among objects in that array:

- (double) detectCollisionsInArray:(NSArray*)objects
{   
    int count = [objects count];
    if (count > 0)
    {       
        double time = CFAbsoluteTimeGetCurrent();
        for (int i = 0; i < count; i++)
        {
            for (int j = i + 1; j < count; j++)
            {
                /** LOTS AND LOTS OF WORK FOR EACH OBJECT **/
            }
        }

        return CFAbsoluteTimeGetCurrent() - time;
    }

    return 0;
}

很简单,并且考虑到问题的限制,它似乎表现良好。然而,我想利用事实,每个对象的状态不在代码部分中修改,并使用GCD并行化这项工作。为此,我尝试这样的:

Pretty straightforward, and it seems to perform well given the constraints of the problem. However, I would like to take advantage of the fact that the state of each object is not modified in the code section and use GCD to parallelize this work. To do this I am trying something like this:

- (double) detectCollisionsInArray:(NSArray*)objects
{   
    int count = [objects count];
    if (count > 0)
    {
        NSOperationQueue* opQueue = [[NSOperationQueue alloc] init];
        NSBlockOperation* blockOperation = nil;

        double time = CFAbsoluteTimeGetCurrent();
        for (int i = 0; i < count; i++)
        {
            for (int j = i + 1; j < count; j++)
            {
                void (^workBlock) (void) = ^() 
                {
                    /** LOTS AND LOTS OF WORK FOR EACH OBJECT **/
                };

                if (!blockOperation)
                {
                    blockOperation = [NSBlockOperation blockOperationWithBlock:b];
                }
                else
                {
                    [blockOperation addExecutionBlock:workBlock];
                }
            }
        }

        [opQueue addOperation:blockOperation];
        [opQueue autorelease];

        return CFAbsoluteTimeGetCurrent() - time;
    }

    return 0;
}

任何人都可以帮助我把正确的轨道,一个好的GCD教程?我已经查看了几个GCD教程和scoured所有的文档,我仍然觉得我对这个问题的掌握是微不足道的。感谢!

Can anyone help to put me on the right track and perhaps provide a link to a good GCD tutorial? I have looked over several GCD tutorials and scoured all of the documentation and I still feel that my grasp on the subject is tenuous at best. Thanks!

推荐答案

有没有理由不使用GCD C API和 dispatch_ * 家庭功能?你不能很好地控制 NSOperationQueue 的GCD方面(就像你要提交块的队列一样)。此外,我无法判断您是否使用iOS,但 NSOperationQueue 不会在iOS上使用GCD。 这可能是它产生了这么多线程的原因。无论如何,如果您直接使用GCD API,代码将会更短,更简单:

Is there a reason you're not using the GCD C API and the dispatch_* family of functions? You don't have much control over the GCD aspects of NSOperationQueue (like which queue you want to submit the blocks to). Also, I can't tell if you're using iOS or not, but NSOperationQueue does not use GCD on iOS. That might be the reason it spawned so many threads. Either way, your code will be shorter and simpler if you use the GCD API directly:

- (double) detectCollisionsInArray:(NSArray*)objects
{   
  int count = [objects count];
  if (count > 0)
  {
    double time = CFAbsoluteTimeGetCurrent();

    dispatch_group_t group = dispatch_group_create();
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    for (int i = 0; i < count; i++)
    {
      dispatch_group_async(group, queue, ^{
        for (int j = i + 1; j < count; j++)
        {
          dispatch_group_async(group, queue, ^{
            /** LOTS AND LOTS OF WORK FOR EACH OBJECT **/
          });
        }
      });
    }
    dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
    dispatch_release(group);
    return CFAbsoluteTimeGetCurrent() - time;
  }
  return 0;
}

您可以使用 dispatch_group 将所有执行分组在一起,并等待所有执行完成 dispatch_group_wait 。如果你不在乎知道块何时完成,你可以忽略组部分,只需使用 dispatch_async dispatch_get_global_queue 函数将获取3个并发队列之一(低,默认或高优先级),以便您提交块。你不必担心限制线程数或类似的东西。 GCD调度程序应该为你做所有这一切。只需确保提交到并发队列,它可以是3个全局队列之一,也可以是通过将 DISPATCH_QUEUE_CONCURRENT 传递给 dispatch_queue_create (这在OS X 10.7和iOS 5.0中可用)。

You can use a dispatch_group to group all of the executions together and wait for them all to finish with dispatch_group_wait. If you don't care to know when the the blocks finish, you can ignore the group part and just use dispatch_async. The dispatch_get_global_queue function will get one of the 3 concurrent queues (low, default or high priority) for you to submit your blocks to. You shouldn't have to worry about limiting the thread count or anything like that. The GCD scheduler is supposed to do all of that for you. Just make sure you submit to a concurrent queue, which could either be one of the 3 global queues, or a queue you've created by passing DISPATCH_QUEUE_CONCURRENT to dispatch_queue_create (this is available starting OS X 10.7 and iOS 5.0).

如果你在每个块中做一些文件I / O或者征税一些其他资源,您可能需要在GCD中统治并限制您一次提交到队列的块数。这将具有与限制 NSOperationQueue 中的并发操作计数相同的效果。您可以使用GCD信号量执行此操作:

If you're doing some file I/O in each block or taxing some other resource, you might need to reign in GCD and limit the number of blocks you're submitting to the queue at once. This will have the same effect as limiting the concurrent operation count in an NSOperationQueue. You can use a GCD semaphore to do this:

- (double) detectCollisionsInArray:(NSArray*)objects
{   
  int count = [objects count];
  if (count > 0)
  {
    double time = CFAbsoluteTimeGetCurrent();

    dispatch_group_t group = dispatch_group_create();
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(10);
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    for (int i = 0; i < count; i++)
    {
      dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
      dispatch_group_async(group, queue, ^{
        for (int j = i + 1; j < count; j++)
        {
          dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
          dispatch_group_async(group, queue, ^{
            /** LOTS AND LOTS OF WORK FOR EACH OBJECT **/
            dispatch_semaphore_signal(semaphore);
          });
        }
        dispatch_semaphore_signal(semaphore);
      });
    }
    dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
    dispatch_release(group);
    dispatch_release(semaphore);
    return CFAbsoluteTimeGetCurrent() - time;
  }
  return 0;
}

一旦你得到它的结束,GCD使用非常简单。我现在使用它的所有代码。

Once you get the hang of it, GCD is very simple to use. I use it all over my code now.


任何人都可以帮助我把正确的轨道,也许提供一个链接到一个好的GCD教程?

Can anyone help to put me on the right track and perhaps provide a link to a good GCD tutorial?

运行,不要过渡到 Mike Ash的博客。他的关于GCD的系列是我看过的最清晰和最简洁的,它只需要大约30分钟阅读整个事情。苹果的WWDC视频从2010年在GCD和块也很不错。

Run, don't walk over to Mike Ash's blog. His series on GCD is the clearest and most concise I've seen, and it'll only take you around 30 minutes to read the whole thing. Apple's WWDC videos from 2010 on GCD And blocks are also pretty good.

这篇关于GCD性能差的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆