【问题标题】:Block Operation - Completion Block returning random results块操作 - 完成块返回随机结果
【发布时间】:2019-07-21 20:13:30
【问题描述】:

我的块操作完成处理程序正在显示随机结果。不知道为什么。我读过这个,所有的课程都说它类似于 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"] - 它随机打印,没有所有预期值

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

【问题讨论】:

    标签: ios swift nsoperation nsblockoperation


    【解决方案1】:

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

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

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

    如果您打开 TSAN,thread sanitizer,(可在“产品”»“方案”»“编辑方案...”中找到,或按 +,然后选择“Run”»“Diagnostics”»“Thread Sanitizer”)它会警告您有关数据争用。


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

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

    【讨论】:

    • (-0.33) 关于串行队列的评论令人困惑——尤其是因为这不是问题所在。正如您所说,BlockOperation 也是并发的 :) - 它是并发的事实似乎是他所看到的 :)
    • @Daij-Djan - “并发的事实似乎是他所看到的”......这就是我明确说明串行队列问题的确切原因。人们很容易将操作队列的串行/并发性质与addExecutionBlock 块的并发执行混淆。一个与另一个无关。不管队列是如何定义的,通过addOperationBlock 为给定操作添加的块可以相互并发运行。我试图澄清。
    猜你喜欢
    • 2012-08-19
    • 1970-01-01
    • 2023-01-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-23
    • 2015-01-14
    • 1970-01-01
    相关资源
    最近更新 更多