以前可能会以不同的形式提出这个问题。但我认为我的看法不同。我正在为整个代码库和大量重构做一些优化任务,这也将为代码的可读性提供服务。
所以我发现[NSThread sleepForTimeInterval:]
方法写在某个地方,因为延迟我总是使用GCD的dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(<#delayInSeconds#> * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{})
方法。那么问题是哪个更好?
答案 0 :(得分:6)
有很大的不同。
[NSThread sleepForTimeInterval:]
阻止当前线程。如果当前线程是主线程,这很糟糕。在其他线程上它可能很好或很糟糕,这取决于你正在做什么。
dispatch_after
不阻止当前线程。该块排队等待将来在指定队列上运行,而当前线程继续以其快乐方式继续运行。
在没有任何特定背景的情况下,我会说dispatch_after
在几乎所有情况下都是更好的方法。
答案 1 :(得分:2)
在考虑将[NSThread sleepForTimeInterval:]
的使用替换为GCD&#39; dispatch_after
时,需要考虑几件事情。正如@rmaddy所说,[NSThread sleepForTimeInterval:]
阻止了它所调用的线程。正如所指出的,这对主线程来说非常糟糕,更常见的是任何带有运行循环的线程(因为在该调用期间运行循环不会迭代。)
如果你有一个带有运行循环的线程,你可以&#34;旋转&#34; 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:]
阻止线程而不是使用更现代的延迟机制的原因。