【问题标题】:Can I control parallelism of concurrentPerform?我可以控制 concurrentPerform 的并行性吗?
【发布时间】:2019-01-19 12:22:55
【问题描述】:

我写了一个例程,使用 DispatchQueue.concurrentPerform(iterations:execute:) 并在多线程编程中使用它。

当我错误地将 queue.sync 的无意义迭代放入另一个函数时,我很惊讶性能会更好。 迭代让 concurrentPerform 在 A12X Bionic 中使用了更多的内核。

当然Apple's document 说,

许多因素会影响并发队列执行的任务数,包括可用内核数、其他进程正在完成的工作量以及其他串行调度队列中的任务数和优先级。

我想以合理的方式获得更好的性能。 如何控制concurrentPerform的并行度?

将队列的 QoS 更改为 .userInitiated 无效。

谢谢。

【问题讨论】:

  • 还有一个优先级更高的QoS .userInteractive,试试看

标签: ios swift grand-central-dispatch


【解决方案1】:

让我们试试吧!下一个示例以两种不同的方式完成简单作业,首先在 .default .concurrent 队列上异步调度所有作业,然后使用 DispatchQueue.concurrentPerform。

DispatchQueue.concurrentPerform 是一个非常漂亮且易于使用的构造。

import Foundation
import PlaygroundSupport

PlaygroundPage.current.needsIndefiniteExecution = true

let q = DispatchQueue(label: "internal", qos: .utility, attributes: .concurrent)
func job()->String {
    var sum  = 0
    for i in 1...1000 {
        let r = Int.random(in: 0..<i)
        sum += r
    }
    let res = sum.description
    return res
}

func asyncFoo(on: DispatchQueue, id: Int, completition: @escaping (_ id: Int, _ result: String)->()) {

    on.async {
        let res = job()
        completition(id, res)
    }
}

let group = DispatchGroup()

var start = Date()

for i in 0..<10 {
    group.enter() // enter the group before the task starts
    asyncFoo(on: q, id: i) { (id, result) in
        print("id:", id, i, result)
        group.leave() // leave the group when task finished
    }
}
group.notify(queue: .main) {
    var stop = Date()
    print("all asynchronously dispatched done in", stop.timeIntervalSince(start), "seconds")
    let task: (Int)->() = { i in
        let res = job()
        print("id:", i, res)
    }
    print("continue again ...")
    start = Date()
    DispatchQueue.concurrentPerform(iterations: 10, execute: task)
    stop = Date()
    print("all .concurrentPerform done in", stop.timeIntervalSince(start), "seconds")
    PlaygroundPage.current.finishExecution()
}
print("continue execution ...")

结果呢?

continue execution ...
id: 7 7 251189
id: 2 2 252628
id: 8 8 248525
id: 5 5 248212
id: 0 0 254412
id: 3 3 255094
id: 6 6 260566
id: 1 1 242460
id: 9 9 247018
id: 4 4 246296
all asynchronously dispatched done in 0.10741996765136719 seconds
continue again ...
id: 2 248549
id: 3 245366
id: 7 242868
id: 8 252247
id: 0 250905
id: 4 249909
id: 6 247525
id: 9 246204
id: 1 253908
id: 5 249081
all .concurrentPerform done in 0.05399894714355469 seconds

如果可用,我更喜欢使用 .concurrentPerform,但这真的取决于...没有 API 可以更改 .concurrentPerform 上的任何内容,但很可能它将是您表现最好的。

【讨论】:

  • 感谢您的回答!你能告诉我如何让concurrentPerform的性能更好吗?这是我的问题。
  • @Yuji,你没有什么需要调整的,我的例子试图告诉你,你自己的设计很可能是最糟糕的。只需“按原样”使用它。操作系统(至少在 Apple 平台上)为您做了“最好的”。如果您担心同步行为,请异步调度整个事情,仅此而已。
  • @Yuji,如果您遇到性能不佳的情况,请向我们展示代码,很可能问题出在其他地方。尽管名称是 .concurrentPerform,但它是为并行执行而设计的
猜你喜欢
  • 2015-09-28
  • 2021-08-01
  • 1970-01-01
  • 2012-04-18
  • 2019-12-14
  • 1970-01-01
  • 1970-01-01
  • 2013-12-30
  • 1970-01-01
相关资源
最近更新 更多