ios - block 操作 - 完成 block 返回随机结果

标签 ios swift nsoperation nsblockoperation

我的 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"] - 它随机打印,没有所有预期值

不知道为什么会这样。请指教

enter image description here

enter image description here

最佳答案

问题是那些独立的执行 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/

相关文章:

ios - Swift 根据文本长度动态增长单元格

objective-c - 如何在 nsstring 中的 '=' 符号后添加双引号?

ios - 如何查找Xcode中发生了哪一行错误?

swift - 如何在 Swift 中从字符集中获取随机元素

ios - 核心数据崩溃: EXC_BAD_ACCESS while trying access data got using predicate

ios - 为什么ios上传文件时没有调用nodejs multer上的onParseEnd回调?

objective-c - 使用 NSOperationQueue 解决读写器问题?

ios - Swift:使用 tableview 创建无限树

ios - 并发操作、NSOperationQueue 和异步 API 所需的说明

ios - 将主队列设置为 NSOperationQueue 的底层队列