GCD主队列和主线程之间有什么区别? [英] What is the difference between GCD main queue and the main thread?

查看:774
本文介绍了GCD主队列和主线程之间有什么区别?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我读了关于SO的评论,分派队列到主线程和在主线程执行代码不一样。如果我正确理解用户说这个

I read comment on SO that dispatching a queue to the main thread is not the same as performing code on the main thread. If I understood correctly the user was saying that this

dispatch_async(dispatch_get_main_queue(),
                 ^{
                      // some code
                 });

与此不同

[self performSelectorOnMainThread:@selector(doStuff)
                       withObject:nil waitUntilDone:NO];

- (void) doStuff {
  // some code
}


b $ b

有这个评论有什么真的吗?

is there some true about this comment?

不包括第一个代码是异步的事实,对我来说,这两个代码在主线程上同样执行。它们之间有什么技术上的差异吗?

Excluding the fact that the first code is asynchronous, for me, both codes are performed equally on the main thread. Is there any technical difference between them?

我问的是,因为我有一些代码使用dispatch_async在主线程更新UI,它不工作,但当我使用performSelectorOnMainThread将其更改为第二个表单。

I am asking that because I had some code to update the UI using dispatch_async on the main thread and it was not working but when I changed that to the second form using performSelectorOnMainThread, it worked.

推荐答案

是的,有区别。主分派队列是一个串行队列。这意味着,当它运行已提交到它的任务时,它不能运行任何其他任务。即使它运行内部事件循环,也是如此。

Yes, there's a difference. The main dispatch queue is a serial queue. That means that, while it's running a task that's been submitted to it, it can't run any other tasks. That's true even if it runs an inner event loop.

-performSelectorOnMainThread:... 资源。

一个例子,在这个例子中,这个位是我的第一个运行循环,运行一个模态文件打开对话框。 (非沙盒,所以对话框正在进行中。)我从提交到主分派队列的任务启动了模态对话框。事实证明,打开对话框的内部实现也会异步地将一些工作分派给主队列。由于主分派队列被我运行对话框的任务占用,它没有处理框架的任务,直到对话框完成之后。症状是对话框将无法显示文件,直到一些内部超时到期,这是大约一分钟左右。

One case where this bit me is with running a modal file open dialog. (Non-sandboxed, so the dialog is in-process.) I initiated the modal dialog from a task submitted to the main dispatch queue. It turns out that the internal implementation of the open dialog also dispatches some work to the main queue asynchronously. Since the main dispatch queue was occupied by my task which was running the dialog, it didn't process the framework's tasks until after the dialog completed. The symptom was that the dialog would fail to show the files until some internal timeout had expired, which was on the order of a minute or so.

请注意,这wasn' t由从主线程对主队列的同步请求引起的死锁的情况,尽管这也可能发生。使用GCD,这样的同步请求肯定会死锁。使用 -performSelectorOnMainThread:... ,不会因为同步请求( waitUntilDone 设置为<$ c $

Note that this wasn't a case of deadlock caused by a synchronous request to the main queue from the main thread, although that can also happen. With GCD, such a synchronous request is certain to deadlock. With -performSelectorOnMainThread:..., it won't because a synchronous request (waitUntilDone set to YES) is just run directly.

顺便说一句,你说第一个代码是异步的,好像与第二代码。两者都是异步的,因为你在第二个传递 NO for waitUntilDone

By the way, you say "the first code is asynchronous" as if to contrast with the second code. Both are asynchronous, since you passed NO for waitUntilDone in the second.

更新:

考虑这样的代码:

dispatch_async(dispatch_get_main_queue(), ^{
    printf("outer task, milestone 1\n");
    dispatch_async(dispatch_get_main_queue(), ^{
        printf("inner task\n");
    });
    // Although running the run loop directly like this is uncommon, this simulates what
    // happens if you do something like run a modal dialog or call -[NSTask waitUntilExit].
    [[NSRunLoop mainRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:1]];
    printf("outer task, milestone 2\n");
});

这将记录:

outer task, milestone 1
outer task, milestone 2
inner task


b $ b

内部任务将不会运行,直到外部任务完成。这是真的,即使外部任务运行主运行循环,这是什么进程任务分派到主队列。原因是主队列是一个串行队列,并且在它仍在运行任务时永远不会启动一个新任务。

The inner task won't get to run until the outer task has completed. That's true even though the outer task ran the main run loop, which is what processes tasks dispatched to the main queue. The reason is that the main queue is a serial queue and will never start a new task while it's still running a task.

如果你改变内部 dispatch_async()到 dispatch_sync(),那么程序将会死锁。

If you change the inner dispatch_async() to dispatch_sync(), then the program will deadlock.

相反,请考虑:

- (void) task2
{
    printf("task2\n");
}

- (void) task1
{
    printf("task1 milestone 1\n");
    [self performSelectorOnMainThread:@selector(task2) withObject:nil waitUntilDone:NO];
    [[NSRunLoop mainRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:1]];
    printf("task1 milestone 2\n");
}

(... in some other method:)
    [self performSelectorOnMainThread:@selector(task1) withObject:nil waitUntilDone:NO];

这将记录:

task1 milestone 1
task2
task1 milestone 2

-task1 中运行运行循环为内部 -performSelectorOnMainThread:... 运行提供机会。

Running the run loop inside of -task1 gives an opportunity for the inner -performSelectorOnMainThread:... to run. This is the big difference between the two techniques.

如果将 NO 更改为 YES -task1 中,这仍然可以无死锁。这是另一个区别。这是因为当 -performSelectorOnMainThread:... waitUntilDone 设置为true时调用,它检查它是否被调用主线程。如果是,那么它只是直接调用选择器。它就好像它只是调用 -performSelector:withObject:

If you change the NO to YES in -task1, this still works without deadlock. That's another difference. That's because, when -performSelectorOnMainThread:... is called with waitUntilDone set as true, it checks if it's called on the main thread. If it is, then it just directly invokes the selector right there. It's as though it were just a call to -performSelector:withObject:.

这篇关于GCD主队列和主线程之间有什么区别?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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