我的 block 操作完成处理程序正在显示随机结果。不知道为什么。我读过这个,所有类(class)都说它类似于 GCD 中的 Dispatch Groups
请在下面找到我的代码
import Foundation
let sentence = "I love my car"
let wordOperation = BlockOperation()
var wordArray = [String]()
for word in sentence.split(separator: " ") {
wordOperation.addExecutionBlock {
print(word)
wordArray.append(String(word))
}
}
wordOperation.completionBlock = {
print(wordArray)
print("Completion Block")
}
wordOperation.start()
我期望我的输出是 ["I", "love", "my", "car"](它应该显示所有这些词——按顺序或随机顺序)
但是当我运行时,我的输出是 ["my"] 或 ["love"] 或 ["I", "car"] - 它随机打印,没有所有预期值
不知道为什么会这样。请指教
最佳答案
问题是那些独立的执行 block 可能在独立的线程上相互并发运行。如果您开始
操作,或者即使您将此操作添加到 maxConcurrentOperationCount
为 1 的操作队列,也是如此。如 the documentation说,在处理 addExecutionBlock
时:
The specified block should not make any assumptions about its execution environment.
除此之外,Swift 数组不是线程安全的。因此,在没有同步的情况下,与非线程安全对象的并发交互可能会导致意外行为,例如您与我们分享的内容。
如果您打开 TSAN,thread sanitizer ,(在“产品”»“方案”»“编辑方案...”中找到,或按⌘+<,然后选择“运行”»“诊断” » “Thread Sanitizer”),它会警告您数据竞争。
因此,归根结底,问题不在于 addExecutionBlock
本身,而是试图同时从多个线程改变数组。如果您将并发队列与调度组结合使用,您可能会遇到类似的问题(尽管与许多竞争条件一样,有时很难表现出来)。
理论上,可以将同步代码添加到您的代码片段中,这样就可以解决问题。但话又说回来,尝试启动一堆并发更新,然后才在其中使用同步来防止并发更新,这将是愚蠢的。它会起作用,但效率低下。仅当后台线程的工作量与同步更新某些共享资源所花费的时间量相比很大时,才采用该模式。但这里不是这种情况。
关于ios - block 操作 - 完成 block 返回随机结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57136657/