swift3 – 长循环块应用程序

swift3 – 长循环块应用程序,第1张

概述我在我的应用程序中跟随循环 var maxIterations: Int = 0func calculatePoint(cn: Complex) -> Int { let threshold: Double = 2 var z: Complex = .init(re: 0, im: 0) var z2: Complex = .init(re: 0, im: 0) 我在我的应用程序中跟随循环

var maxIterations: Int = 0func calculatePoint(cn: Complex) -> Int {    let threshold: Double = 2    var z: Complex = .init(re: 0,im: 0)    var z2: Complex = .init(re: 0,im: 0)    var iteration: Int = 0    repeat {        z2 = self.pow2ForComplex(cn: z)        z.re = z2.re + cn.re        z.im = z2.im + cn.im        iteration += 1    } while self.absForComplex(cn: z) <= threshold && iteration < self.maxIterations    return iteration}

并且在循环执行期间显示彩虹轮.我如何管理该应用程序仍在响应UI *** 作?
注意我在循环运行时在代码的不同部分更新了nsprogressIndicator,但没有更新(进度未显示).
我怀疑它与调度有关,但我对此非常“绿色”.我非常感谢任何帮助.
谢谢.

解决方法 要异步调度某些内容,请在相应的队列上调用async.例如,您可以更改此方法以在全局后台队列上执行计算,然后将结果报告回主队列.顺便说一句,当你这样做时,你从立即返回结果转移到使用完成处理程序关闭,异步方法将在计算完成时调用:

func calculatePoint(_ cn: Complex,completionHandler: @escaPing (Int) -> VoID) {    dispatchQueue.global(qos: .userInitiated).async {        // do your complicated calculation here which calculates `iteration`        dispatchQueue.main.async {            completionHandler(iteration)        }    }}

你会这样称呼它:

// start nsprogressIndicator herecalculatePoint(point) { iterations in    // use iterations here,noting that this is called asynchronously (i.e. later)    // stop nsprogressIndicator here}// don't use iterations here,because the above closure is likely not yet done by the time we get here;// we'll get here almost immediately,but the above completion handler is called when the asynchronous// calculation is done.

马丁猜测你正在计算一个Mandelbrot集.如果是这样,将每个点的计算分派到全局队列并不是一个好主意(因为这些全局队列将其块分派给工作线程,但这些工作线程非常有限).

如果要避免耗尽所有这些全局队列工作线程,一个简单的选择是从计算单个点的例程中取出异步调用,然后只调度遍历所有复杂值的整个例程到a后台线程:

dispatchQueue.global(qos: .userInitiated).async {    for row in 0 ..< height {        for column in 0 ..< wIDth {            let c = ...            let m = self.mandelbrotValue(c)            pixelBuffer[row * wIDth + column] = self.color(for: m)        }    }    let outputCGImage = context.makeImage()!    dispatchQueue.main.async {        completionHandler(NSImage(cgImage: outputCGImage,size: NSSize(wIDth: wIDth,height: height)))    }}

这解决了“让它脱离主线程”和“不要耗尽工作线程”的问题,但现在我们已经摆脱了使用太多的工作线程,只使用一个工作线程,没有充分利用设备.我们真的希望并行执行尽可能多的计算(而不是耗尽工作线程).

在为复杂计算执行for循环时,一种方法是使用dispatch_apply(现在在Swift 3中称为concurrentPerform).这就像一个for循环,但它相互之间并发地执行每个循环(但最后,等待所有这些并发循环完成).为此,请使用concurrentPerform替换外部for循环:

dispatchQueue.global(qos: .userInitiated).async {    dispatchQueue.concurrentPerform(iterations: height) { row in        for column in 0 ..< wIDth {            let c = ...            let m = self.mandelbrotValue(c)            pixelBuffer[row * wIDth + column] = self.color(for: m)        }    }    let outputCGImage = context.makeImage()!    dispatchQueue.main.async {        completionHandler(NSImage(cgImage: outputCGImage,height: height)))    }}

concurrentPerform(以前称为dispatch_apply)将同时执行该循环的各种迭代,但它会自动优化设备功能的并发线程数.在我的MacBook Pro上,这使得计算速度比简单的for循环快4.8倍.注意,我仍然将整个事务调度到全局队列(因为concurrentPerform同步运行,我们从不想在主线程上执行慢速,同步计算),但concurrentPerform将并行运行计算.这是一种在for循环中享受并发性的好方法,这样你就不会耗尽GCD工作线程.

顺便说一句,你提到你正在更新nsprogressIndicator.理想情况下,您希望在处理每个像素时更新它,但如果这样做,UI可能会积压,无法跟上所有这些更新.您最终会减慢最终结果,以便UI能够赶上所有这些进度指示器更新.

解决方案是将UI更新与进度更新分离.您希望背景计算在每个像素更新时通知您,但您希望更新进度指示器,每次有效地说“好,从我上次检查后计算的像素数更新后更新进度”.有一些繁琐的手工技术可以做到这一点,但GCD提供了一个非常优雅的解决方案,一个调度源,或更具体地说,dispatchSourceUserDataAdd.

因此,定义调度源的属性和计数器,以跟踪到目前为止已处理的像素数:

let source = dispatchSource.makeUserDataAddSource(queue: .main)var pixelsProcessed: UInt = 0

然后为调度源设置事件处理程序,以更新进度指示器:

source.setEventHandler() { [uNowned self] in    self.pixelsProcessed += self.source.data    self.progressIndicator.doubleValue = Double(self.pixelsProcessed) / Double(wIDth * height)}source.resume()

然后,在处理像素时,您只需从后台线程添加到源代码:

dispatchQueue.concurrentPerform(iterations: height) { row in    for column in 0 ..< wIDth {        let c = ...        let m = self.mandelbrotValue(for: c)        pixelBuffer[row * wIDth + column] = self.color(for: m)        self.source.add(data: 1)    }}

如果这样做,它将以尽可能高的频率更新UI,但它永远不会被更新队列积压.调度源将为您合并这些添加调用.

总结

以上是内存溢出为你收集整理的swift3 – 长循环块应用程序全部内容,希望文章能够帮你解决swift3 – 长循环块应用程序所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/web/999823.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2022-05-21
下一篇2022-05-21

发表评论

登录后才能评论

评论列表(0条)

    保存