【问题标题】:How to ensure two gcd queues run on separate threads?如何确保两个 gcd 队列在不同的线程上运行?
【发布时间】:2013-07-13 23:52:50
【问题描述】:

我想确保两个队列最终在不同的线程上执行。理想情况下,我想确保它们是串行队列。特别是,在下面的示例中,如果两个队列在同一个线程上运行,doStuff 将无限期地忙于等待。我将不得不转向显式线程还是可以在这里挽救 GCD 的使用?

- (void)foo {
    self.responseQueue = dispatch_queue_create("com.blah.response", DISPATCH_QUEUE_SERIAL);

    self.requestQueue = dispatch_queue_create("com.blah.request", DISPATCH_QUEUE_SERIAL);

    dispatch_async(self.requestQueue, ^{
        [self doStuff];
    });
}

- (BOOL)doStuff {
    BOOL __block waiting = YES;

    self.responseBlock = ^{
        waiting = NO;
    };

    [self performRequest];

     while (waiting) {
         // realize could use dispatch_semaphore (busy waiting just to illustrate point).    
         sleep(1);
     }

     [self doStuffRequiringResponseCompletion];

     // I realize it would be sensible to 
     // 1) Not block in the above while loop.
     // 2) Call |doStuffRequiringResponseCompletion| after |receivedResponse|.
     // I don't want to do this.
}

// method called on arbitrary thread
- (void)receivedResponse {
    // stuff

    dispatch_async(self.responseQueue, self.responseBlock);
}

另请参阅:Is there any reason to not use sleep in a Grand Central Dispatch queue??

【问题讨论】:

  • performRequest 神奇地调用 receivedResponse 并不直观。如果 performRequest 失败,您应该使用超时。当请求/响应是同一串行操作的一部分时,为什么要使用两个串行队列进行请求/响应?为什么是全局响应块?为什么要异步和阻塞? GCD 的存在是为了避免显式线程的复杂性。如果您解释您的用例,您将获得更好设计的建议。

标签: objective-c grand-central-dispatch


【解决方案1】:

您无法确保它们在不同的线程上运行——调度队列的关键在于操作系统为您管理线程。但是,除非您正在做一些真正需要在特定线程上运行的高度专业化的工作,否则串行调度队列的默认行为应该对您非常有用。如果您确实需要确保特定线程,那么您将重新使用 NSThread。

【讨论】:

  • 任何控制 GCD 块在哪些线程上执行的努力,即使看似成功,最终也是徒劳的。此外,在提交给 GCD 的块中忙于等待(即调用 sleep())暴露了糟糕的设计。 OP 应该使用不同的方法重新考虑这一点。
【解决方案2】:

调度队列未绑定到线程。如果您的调度项目之一阻塞了一个线程,GCD 将使用或创建其他线程来处理其他队列(以及此队列中的其他项目,如果它是并发队列)。

GCD 将创建的线程数有上限。如果您有太多像这样休眠的调度项,那么您可能会遇到该限制并可能出现死锁。

【讨论】:

    【解决方案3】:

    你应该避免阻塞线程。使用您的示例,在您的响应块中,处理响应后,您可以将另一个块排入 com.blah.request 以执行您正在等待执行的任何操作。

    【讨论】:

    • 我意识到这是明智之举,但在这里我想在 responseQueue 执行时阻止 requestQueue。
    • 那么我想知道为什么你有两个单独的队列?或者您是否考虑过将请求和响应队列都定位到单个串行队列(3 的小层次结构)?也许您可以更多地描述用例,我敢打赌有一个比阻塞线程更优雅的解决方案。
    • 这本质上是我正在进行的串行操作,因此您的原始建议是最好的。我想要一个骇人听闻的解决方案来在不同的线程上强制执行两个队列。 (应该澄清:我希望一个队列阻塞另一个队列)
    • @Ehreh 阅读了这篇关于多位读者和一位作者的帖子。我认为它可能会做你想做的事,而不是试图强迫 GCD 做一些它不打算做的事情。 objc.io/issue-2/…
    【解决方案4】:

    我不建议使用这个解决方案,因为调度队列不应该被滥用于同步目的,但我所追求的是这样的事情(但是这不能保证不会死锁 - 如果 dispatch_sync 块运行在与 performSelectorInBackground 启动的线程不同):

    - (void)foo {
        self.responseQueue = dispatch_queue_create("com.blah.response", DISPATCH_QUEUE_SERIAL);
    
        self.requestQueue = dispatch_queue_create("com.blah.request", DISPATCH_QUEUE_SERIAL);
    
        [self performSelectorInBackground:@selector(dispatchRequest) withObject:nil]
    }
    
    - (void)dispatchRequest {
        dispatch_sync(self.requestQueue, ^{
            [self doStuff];
        });
    }
    

    【讨论】:

      猜你喜欢
      • 2021-11-17
      • 1970-01-01
      • 1970-01-01
      • 2010-12-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-02-01
      • 1970-01-01
      相关资源
      最近更新 更多