如何仅在一个线程上运行任务? [复制]

Posted

技术标签:

【中文标题】如何仅在一个线程上运行任务? [复制]【英文标题】:How to run tasks on one thread only? [duplicate] 【发布时间】:2019-07-10 09:29:18 【问题描述】:

假设我有几个数据库写入闭包,我想在单个线程上执行它们,但不是作为批处理 - 我需要在每次写入后更新 UI。

串行队列如:

DispatchQueue.global(qos: .background).async 

DispatchQueue(label: "hello world").async 

在他们想要运行的任何线程中运行,但可以串行运行。

我怎样才能有一个只在一个后台线程上运行的队列?

【问题讨论】:

在哪个线程上运行有什么关系,只要它不是主线程?用例是什么? 使用一个核心数据上下文或一个领域。 在上下文中使用执行块时,我可以在 CoreData 的任何线程上进行任何工作而不会出错。它在自己的队列上执行它的工作。我认为你在尝试在 1 个线程上执行时犯了一个错误。在哪个线程上执行某事并不重要,重要的是队列。 感谢您的努力,如果您可以提供您的方法的代码示例,这将非常有帮助,但 Realm 仅在一个线程中使用时仍然具有显着的性能优势。而且我真的很好奇存档这种行为的方法。 看起来确实是重复。但仍然没有答案。 【参考方案1】:

正如其他人所指出的,代码运行在哪个线程上并不重要。此类性能问题通常取决于简单地按顺序运行任务,一次一个,因此它们不会与资源重叠或冲突。

最简单的解决方案是创建一个顺序队列。 (在 Safari 中输入,因此值得您为此付出的每一分钱)

let queue = DispatchQueue(label: "db.update", qos: .utility, attributes: [], autoreleaseFrequency: .inherit, target: nil)

var progress: Int = 0

queue.async 
    // Dome some work, then update the UI
    progress = 2
    DispatchQueue.main.async(execute: 
        // label.text = "did something"
        // progress.doubleValue = Double(progressCounter)
    )


queue.async 
    // Do some more work
    progress += 1
    // This won't execute until the first block has finished


queue.async 
    // Even more work
    progress += 1


queue.async 
    // And so on...
    progress += 1   // This block might, for example, notify the system that everything has finished
    print("progress is finally \(progress)")

关键是每个块都按顺序执行(因为队列不是“并发”的),直到前一个块完成后才会开始下一个块。每个块可能会或可能不会在同一个线程上执行,但这并不重要。

一个块的结果/进度可以很容易地通过闭包变量传递给下一个块。

【讨论】:

假设我有一个返回数字 N 的请求,并且在收到它时会产生 N 个请求,每个请求依次是 M 个请求,依此类推。我有一个进度指示器,显示总数和加载的数量。我必须解析数据并将其保存在后台以保持我的指标响应。问题不在于数据的一致性 - 如果写入是串行执行的,则没有问题,它与持久 API 的技术方面有关。 如果我有一个 NSManagedObjectContext 或一个 Realm 用于存储记录的一个异步结果和另一个在通过网络发送之前读取它的请求,它们最终将处于不同的线程中(很可能)。如果您使用核心数据并发调试标志运行架构,这将失败。使用 Realm,我不确定您是否会看不到以前的记录。所以我想说的是,当您有非平凡的网络请求树时,使用模型/存储/上下文集成它们的结果和参数非常方便。 否则在闭包之间传递东西并同步它们的结果是非常乏味的。我个人最终为每个请求提供了一个单独的 NSManagedObjectContext,然后将 NSManagedObjectID 从一个闭包传递到另一个闭包,以在未来的请求闭包中获取数据。 使用闭包变量可以很容易地在块之间共享结果。我将更新示例代码以显示这一点。 @Rob,你是对的,那些应该是async 电话。在 Safari 中编写代码的危害...我将更新代码以反映这一点。

以上是关于如何仅在一个线程上运行任务? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

OpenMP 矩阵向量乘法仅在一个线程上执行

如何在 C# 中使用 TaskScheduler 设置“仅在登录时运行”和“运行方式”?

如何仅在修改后的文件上运行 tslint

创建的线程数为 12,但仍仅在 12 核 CPU 中的一个核上运行

如何检查是不是在 Android 的 UI 线程上运行? [复制]

Windows 任务计划程序 - 仅在时间窗口内运行