Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/105.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios 理解并发GCD_Ios_Multithreading_Asynchronous_Gcdasyncsocket - Fatal编程技术网

Ios 理解并发GCD

Ios 理解并发GCD,ios,multithreading,asynchronous,gcdasyncsocket,Ios,Multithreading,Asynchronous,Gcdasyncsocket,问题很简单,但我没有找到合理的答案。 在这样的代码中 dispatch_queue_t background_queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, NULL); dispatch_async(background_queue, ^{ // do some stuff that takes a long time here... // follow up with some stuff on

问题很简单,但我没有找到合理的答案。 在这样的代码中

dispatch_queue_t background_queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, NULL);

dispatch_async(background_queue, ^{
// do some stuff that takes a long time here...

    // follow up with some stuff on the main queue
    dispatch_async(dispatch_get_main_queue(), ^{
        // Typically updating the UI on the main thread.
    });

});
后台队列是一个并发队列,因此它内部的任务将按顺序启动,但可能不会按相同的顺序完成。因此,我们可以在下载图像之前调用更新UI的块。
更多的澄清会很有帮助,谢谢。

好吧,我想我不能在这个简短的回答中完全解释GCD机制,但我会给出一个简短的总结:

有串行队列和并发队列:

串行队列采用先进先出的方式。 并发队列不保证任务完成甚至开始的顺序。 然后,有两种工作项排队:异步和同步。这是指呼叫将如何返回:

异步调用通常会在工作项启动或完成之前返回。 同步调用将在工作项完成后返回。 例如,如果将与当前队列同步的工作项排入队列,这将导致死锁


但是在GCD中还有更多的方法,例如,您可以将工作项分组并等待所有工作项完成,或者您可以启动优先级别较高的工作项。

在本例中,两个GCD块将按顺序完成,因为外部块只会在长进程完成后调用内部块,以使其更加正确,所以它可能应该是内部块上的dispatch_sync

这将保证顺序,因为后台线程将在其即将完成之前调用主线程的gcd块,并且只有在长任务完成之后

dispatch_async(background_queue, ^{
// do some stuff that takes a long time here...

    // follow up with some stuff on the main queue
    dispatch_sync(dispatch_get_main_queue(), ^{ //should be sync not async, but in practice should have little impact if nothing happens after this block
        // Typically updating the UI on the main thread.
    });
});
这不会,因为两个gcd块将同时执行,并且不会等待对方完成

dispatch_async(background_queue, ^{
// do some stuff that takes a long time here...
});
// follow up with some stuff on the main queue
dispatch_async(dispatch_get_main_queue(), ^{
   // Typically updating the UI on the main thread.
});

长任务完成后,您将返回主队列。 我将向您展示我使用过的应用程序中的一个示例:

- (void)coinRequest {
    dispatch_queue_t coinsQueue = dispatch_queue_create("getUserCoins", NULL);
    dispatch_async(coinsQueue, ^{
        EMGetUserCoinsRequest* request = [EMGetUserCoinsRequest new];
        __weak typeof(self) _self = self;
        [self putCurrentRequest:request];
        request.suppressLoadingView = YES;
        [BackEnd() performRequest:request force:YES onSuccess:^(EMGetUserCoinsResponse *response) {

            dispatch_async(dispatch_get_main_queue(), ^{

                // Update the UI
                if (response.coins.coins != NULL) {
                    _self.coinsLabel.text = [NSString stringWithFormat:@"%@", response.coins.coins];
                } else {
                    _self.coinsLabel.text = [NSString stringWithFormat:@"0"];
                }
          });

        } onApplicativeError:NULL onEnvironmentError:NULL];
    });
}

正如你所见,我有一个请求,要求用户的硬币。因为UI必须保持响应,所以我使用bg队列。下载信息后,在onSuccess块中,我返回到主线程以更新UI。

在操场上玩

import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution = true

import Foundation

var s0 = ""
var s1 = ""

let queue = DispatchQueue(label: "cq", attributes: .concurrent)


let worker0 = { ()->() in
    for i in 0..<5000 {
        if (i % 1000) == 0 {
                print(i / 1000, terminator: "", to: &s0)
        }
    }
}

let worker1 = { ()->() in
    for i in 0..<5000 {
        if (i % 1000) == 0 {
                print(i / 1000, terminator: "", to: &s1)
        }
    }
}

queue.async(execute: {
    worker0()
    worker0()
    worker0()
    worker0()
    print(s0, " all workers0 were executed serialy")
})

let dg = DispatchGroup()

queue.async(group: dg, execute: worker1)
queue.async(group: dg, execute: worker1)
queue.async(group: dg, execute: worker1)
queue.async(group: dg, execute: worker1)

dg.wait()

print(s1, " workers1 were executed concurrently")

调度到任何队列的执行块中写入的所有代码都是串行执行的

,但在这里,后台队列是一个并发队列,那么为什么UI块要等待长进程?如果UI块不等待长进程,它将尝试在您返回数据之前更新UI,这发生在我发布的第二个代码块中,因此您的UI不会显示您的长过程应该得到的结果,因此UI块可能会在检索数据之前执行,那么,为什么当数据到达时,UI块会被更新,而它在数据到达之前就已经被执行了?我不确定是否会这样做,这可能只是因为UI块恰好在长任务块之后运行,但您不能保证总是这样。另一种情况可能是,您多次调用这两个块,在这种情况下,用户界面将被更新,但这是一种非常意外的方式。我认为同步无法完成此任务,我认为我们应该将后台队列标记为串行,因为并发的区别在于不能保证哪一个将首先完成。下载数据的队列是串行的还是并发的?在我所附的示例中,不能保证UI块将在长过程后运行,是吗?如果你把你的调度呼叫嵌套起来,它会的。所以如果调度\u同步调度\u获取\u主队列。。。是dispatch\u asyncbackground\u队列中的最后一条语句…-call,保证在后台队列中完成所有工作后调用它。这很奇怪,即使后台队列是并发的?这违反了并发队列的定义!并发性只有在它们同时发生时才生效,如果一个线程在执行结束时执行,启动另一个线程,那么即使它们是并发线程,它们仍在一个接一个地手动执行。这种情况下的并发性意味着其他事情可以与这个线程同时发生,但是一旦一个线程完成,手动调用另一个线程与并发性没有任何关系。实际上,这只是执行顺序。您在这里讨论的是dispatch\u sync not concurrent的定义。也就是说,你启动了一些东西并控制回你自己。
00101212323434041234  workers1 were executed concurently
01234012340123401234  all workers0 were executed serialy