1

我的块操作完成处理程序正在显示随机结果。不知道为什么。我读过这个,所有的课程都说它类似于 GCD 中的调度组

请在下面找到我的代码

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

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

在此处输入图像描述

在此处输入图像描述

4

1 回答 1

1

问题是这些单独的执行块可能在单独的线程上相对于彼此同时运行。如果您start像您一样进行操作,或者即使您将此操作添加到 1 的操作队列中maxConcurrentOperationCount也是如此。正如文档所述,在处理时addExecutionBlock

指定的块不应对其执行环境做出任何假设。

最重要的是,Swift 数组不是线程安全的。因此,在没有同步的情况下,与非线程安全对象的并发交互可能会导致意外行为,例如您与我们共享的内容。

如果您打开 TSAN,线程清理器,(在“产品”»“方案”»“编辑方案...”中找到,或按⌘</kbd>+<, and then choose “Run” » “Diagnostics” » “Thread Sanitizer”) it will warn you about the data race.


因此,归根结底,问题addExecutionBlock本身不在于,而在于尝试同时从多个线程中改变数组。如果您将并发队列与调度组一起使用,您可能会遇到类似的问题(尽管像许多竞争条件一样,有时很难表现出来)。

从理论上讲,可以将同步代码添加到您的代码片段中,这样就可以解决问题。但是话又说回来,尝试启动一堆并发更新是愚蠢的,然后才在其中使用同步来防止并发更新。它会起作用,但效率低下。仅当后台线程上的工作与同步更新到某些共享资源所花费的时间相比相当多时,才使用该模式。但这里不是这样。

于 2019-07-21T21:11:03.343 回答