【问题标题】:dispatch_queue_t is serial queue then why does it even exists in multi-task concept?dispatch_queue_t 是串行队列,那么为什么它甚至存在于多任务概念中?
【发布时间】:2014-11-05 01:15:34
【问题描述】:

我是 iPhone 开发的新手,并且正在研究多线程的 GCD 概念。

'dispatch_queue_t' 创建一个串行队列,我读到串行队列一次只能执行一个作业。 GCD 的目的是同时执行多个任务,那为什么还存在串行队列呢?

例如,我想做 2 个任务。任务 A 和任务 B。我创建了一个串行队列来执行这两个任务。我在主队列中执行此操作。这是我正在做的代码:

dispatch_queue_t my_serial_queue = dispatch_queue_create("queue_identifier", 0);

    dispatch_sync(my_serial_queue, ^{
        NSLog(@"Task 1");
    });

    dispatch_sync(my_serial_queue, ^{
        NSLog(@"Task 2");
    });

现在,根据规则,两个任务都将串行执行,因为它是串行队列,即首先执行任务 A,然后在任务 A 完成后执行任务 B。它还在日志中给了我相同的输出。

所以,我的问题是,如果我想同时执行这两个任务怎么办?如果这个问题的答案是为任务 B 创建另一个串行队列,那么代码的结构应该是这样的:

dispatch_queue_t my_serial_queue_1 = dispatch_queue_create("queue_identifier_1", 0);
dispatch_queue_t my_serial_queue_2 = dispatch_queue_create("queue_identifier_2", 0);


    dispatch_sync(my_serial_queue_1, ^{
        NSLog(@"Task 1");
    });

    dispatch_sync(my_serial_queue_2, ^{
        NSLog(@"Task 2");
    });

我得到相同的输出。原因是我使用“dispatch_sync”调用而不是“dispatch_async”调用。但是当我在不同的队列中运行这两个任务时,它们不应该同时执行吗?如果不是,那我们为什么要创建一个不同的队列?我可能通过“dispatch_async”调用使用了相同的队列来同时执行这两个任务。

我真的需要这个问题的答案,因为在我将来设计多任务应用程序的结构之前,它会更好地指导我。

【问题讨论】:

    标签: ios multithreading grand-central-dispatch multitasking nsthread


    【解决方案1】:

    您的困惑几乎完全是因为您使用的是 dispatch_sync。 dispatch_sync 不是一个获取并发执行的工具,它是一个为了安全起见临时限制它的工具。

    使用 dispatch_async 后,您可以通过拥有多个队列或使用并发队列来获得并发性。在这种情况下使用串行队列的目的是控制同时完成哪些工作。

    考虑以下非常愚蠢的例子:

    __block void *shared = NULL;
    for (;;) {
        dispatch_async(aConcurrentDispatchQueue, ^{
            shared = malloc(128);
            free(shared);
        }
    }
    

    这将崩溃,因为最终,两个同时执行的块将连续释放“共享”。这显然是一个人为的例子,但在实践中,几乎所有共享的可变状态都不能同时更改。串行队列是确保您这样做的工具。

    总结:

    • 当您的块中的工作真正独立且线程安全且纯计算时,请继续使用 dispatch_async 到并发队列
    • 如果您有逻辑上独立的任务,每个任务都由多个相关块组成,请为每个任务使用串行队列
    • 当您有访问共享可变状态的工作时,请在串行队列上的 dispatch_sync()ed 块中执行这些访问,并在并发队列上执行其余工作
    • 当你需要做UI相关的工作时,dispatch_asyncdispatch_sync到主队列,看你是否需要等待它完成

    【讨论】:

    • @Catfish_Man:所以简而言之,如果我想完全同时执行 2 个任务(我提到的那些),我应该(1)在串行队列中使用 'dispatch_async' 或(2)创建 2 个并发这 2 个任务的队列,而不是通过“dispatch_queue_t”创建 2 个队列(因为“dispatch_queue_t”创建串行队列)。
    • @Catfish_Man:假设这两个任务是完全独立的。
    • 一个并发队列,或两个串行队列。串行队列对它们上的所有内容进行排序,但相对于所有其他队列是并发的。并发队列根本不会对它们进行排序。
    • @Catfish_Man:我在第一条评论中提到了两种选择。这些解决方案是我想要的吗?
    • 不,我在纠正你。你说两个并发队列,你要么想要两个串行队列,要么一个并发队列。
    【解决方案2】:

    'dispatch_queue_t' 不会创建任何东西。 dispatch_queue_t 一个调度队列,可以是串行的,也可以是并发的。

    dispatch_queue_create 有两个参数。第二个参数决定它创建的队列是串行队列还是并发队列。但通常您不会自己创建并发队列,而是使用现有的三个并发队列之一。

    dispatch_sync 在队列中调度一个块并等待该块完成。很明显,这在很大程度上限制了并发性。你应该几乎总是使用 dispatch_async。

    顺序队列一次只能执行一个块。很明显,这在很大程度上限制了并发性。当您需要一个接一个地执行各种块时,顺序队列仍然很有用,并且它们可以与其他队列中的块并发执行。

    因此,为了最大限度地利用处理器,请在并发队列上使用 dispatch_async。并且不需要创建多个并发队列。是并发的。它可以同时运行任意数量的块。

    【讨论】:

    • @gnasher729:您的声明:“当您需要一个接一个地执行各种块时,顺序队列仍然有用,并且它们可以与其他队列中的块并发执行。”为了使其实用,我通过创建 2 个串行队列进行了演示。但是这些队列不会同时执行。队列 B 的块在 A 中的所有块完成执行之前不会执行。我什至尝试让这两个队列并发,但我得到了相同的结果。为什么在我调用 dispatch_async 之前这些队列不能同时运行? (即使我创建并发队列)
    • 如果你使用dispatch_sync(第一个块),dispatch_sync(第二个块),那么dispatch_sync本身会一直等到第一个块完成,而dispatch_sync(第二个块)只有在第一个块完成后才会执行。如果你这样使用它,队列在做什么并不重要。
    猜你喜欢
    • 2014-10-20
    • 1970-01-01
    • 2020-10-20
    • 1970-01-01
    • 2011-04-25
    • 2010-12-15
    • 2010-11-24
    • 1970-01-01
    • 2016-08-30
    相关资源
    最近更新 更多