繁体   English   中英

睡NSThread Vs. GCD派遣之后

[英]Sleeping NSThread Vs. GCD dispatch after

也许这个问题之前已经以不同的形式提出过。 但我认为我的看法不同。 我正在为整个代码库和大量重构做一些优化任务,这也将为代码的可读性提供服务。

所以我发现在某处编写了[NSThread sleepForTimeInterval:]方法,并且对于延迟,我总是使用GCD的dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(<#delayInSeconds#> * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{})方法。 那么问题是哪个更好?

这是一个巨大的差异。

[NSThread sleepForTimeInterval:]

阻止当前线程。 如果当前线程是主线程,这很糟糕。 根据你在做什么,它可能在其他线程上很好或很糟糕。

dispatch_after

不会阻止当前线程。 该块排队等待将来在指定队列上运行,而当前线程继续以其快乐方式继续。

没有任何特定的上下文,我会说dispatch_after几乎在所有情况下都是更好的方法。

当考虑用GCD的dispatch_after替换[NSThread sleepForTimeInterval:]使用时,有几件事需要考虑。 正如@rmaddy所说, [NSThread sleepForTimeInterval:]阻塞调用它的线程。 正如所指出的,这对主线程来说非常糟糕,更常见的是任何带有运行循环的线程(因为在该调用期间运行循环不会迭代。)

如果你有一个带有运行循环的线程,你可以“旋转”runloop一段时间,这允许其他运行循环源保持响应,同时执行的调用线程仍然被有效阻止。 旋转运行循环的细节超出了问题的范围,但是使用运行循环是解决此问题的另一种方法(尽管如果您没有被其他依赖的其他API推迟使用运行循环,GCD可能仍然是首选在他们身上,例如, NSStream 。)

避免使用[NSThread sleepForTimeInterval:]阻塞线程的主要高级原因是线程是有限的资源。 如果你要创建一个循环产生许多线程,所有这些线程随后因调用[NSThread sleepForTimeInterval:]而被阻塞,你最终将无法创建更多线程。 线程耗尽对于框架中特别优雅的解决方案来说不是问题,因为通常情况下,框架期望您在架构级别通过使用更好的抽象(如GCD或运行循环)来避免线程耗尽。

另一种情况是[NSThread sleepForTimeInterval:]dispatch_after大不相同的是当有线程本地存储在播放时。 如果你的代码做了类似[[NSThread currentThread] threadDictionary][@"foo"] = @"bar"; 然后在[NSThread sleepForTimeInterval:]返回后,您将在完全相同的线程上,因此您放入线程本地存储的值仍然存在。 使用dispatch_after ,无法保证您的块将在与其排队的同一线程上运行。 (并且在飞行中具有其他后台任务的过程中,偶然发生这种情况的总体可能性相当低。)一般来说,将TLS与GCD一起使用并不是一个好主意。 这通常是正常的,因为在块闭包中捕获变量的能力可以解决人们历史上使用TLS解决的许多问题。

线程本地存储是解决给定问题时非常有用的东西之一,但是在面对像这样的重构时会使代码变得脆弱。 更糟糕的是,您可能无法知道代码的其他部分依赖于TLS,除非看到事情失败(或行为怪异)。

长话短说,这里没有足够的信息说哪种机制最适合你的情况。 如果一个人从头开始,我很难想到一个人会选择使用[NSThread sleepForTimeInterval:]而不是使用更现代的延迟机制来阻止线程的原因。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM