- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我试图了解 Swift 中 async-await
的正确应用。假设一个async
方法,一种不进行外部调用的非IO方法,从后台线程调用来执行其进程,例如一些繁重的图像处理方法。
func processImage(image: UIImage) async -> UIImage {
///
}
Task {
let result = await processImage(image: image)
}
当代码暂停并等待结果时发生了什么?由于它不进行外部调用,因此该过程必须在线程池内的某个位置完成。由于它不是在调用该方法的线程中完成的,因此它必须在另一个线程上执行。是否创建子任务来执行流程?据我了解,Task
是一个并发单位,单个任务不包含并发(async let
除外),所以这让我有点困惑。任务是并发还是非并发?
据我所知,如果从主线程调用此方法,async
方法的非阻塞方面会释放线程以供 UI 元素运行,从而提供无缝的视觉体验。但是,从后台线程调用异步方法有什么好处呢?我不是指能够返回结果或抛出错误的语法糖。如果该方法是从后台调用的非 IO 方法,那么与使用同步方法相比,非阻塞方面是否有任何好处?换句话说,它不阻塞什么?如果它是一个并行进程,它会利用更多的资源来有效地处理多个事物,但我不确定在这种情况下并发进程有什么好处。
最佳答案
如果您想使用async/await
,您需要停止考虑线程。在某种程度上,出于显而易见的原因,继续使用“在主线程上”和“在后台线程上”等短语是有用的,但这些几乎都是隐喻。
您只需要接受这一点,无论什么“线程”运行,await
都有神奇的力量说“保留我的位置”并允许计算机走开并执行某些操作直到我们等待的东西回到我们身边为止。没有任何东西阻挡,没有任何东西旋转。这确实是 async/await
要点的很大一部分。
(如果你想了解它在幕后是如何工作的,你需要找出什么是“延续”。但总的来说,这真的不值得担心;这只是让你的内部信仰体系井然有序的问题.)
然而,async/await
的总体优势是语法上的,而不是机械上的。也许您可以通过使用其他机制(Combine、DispatchQueue、Operation 等等)来完成实际上通过async/await
可以完成的所有操作。但经验表明,尤其是在 DispatchQueue 的情况下,初学者(和不太初学者)有 great difficulty reasoning关于异步代码时代码行的执行顺序。使用async/await
,这个问题就消失了:代码按照它出现的顺序执行,就好像它根本不是异步的一样。
不仅仅是程序员; 编译器无法推断 DispatchQueue 代码的正确性。它无助于让你犯错误(我确信你曾经犯过一些错误;我当然也犯过)。但async/await
不是那样的;恰恰相反:编译器可以推理您的代码,并可以帮助保持一切整洁、安全和正确。
对于您提出的实际示例,正确的实现是定义一个参与者,其工作是执行耗时的任务。根据定义,这不会是主要 Actor ;因为你定义了它,所以它就是我们所说的背景 Actor ;它的方法将自动从主线程中调用,并且由于编译器的出色,其他一切都将随之而来。
这是一个示例(来 self 的书),它正在做您所要求的那种事情 - 耗时的计算。这是一个 View ,当您调用其公共(public) drawThatPuppy
方法时,它会计算启动主线程的 Mandelbrot 的粗略图像,然后在其自身内描绘该图像。出于您的目的,需要注意的关键是在行中
self.bitmapContext = await self.calc.drawThatPuppy(center: center, bounds: bounds)
self.setNeedsDisplay()
短语self.bitmapContext =
和self.setNeedsDisplay
在主线程上执行,但对self.calc.drawThatPuppy
的调用在后台线程上执行,因为 calc 是一个参与者。然而,当 self.calc.drawThatPuppy 执行时,主线程并没有被阻塞;相反,其他主线程代码在此期间可以自由运行。这真是一个奇迹!
// Mandelbrot drawing code based on https://github.com/ddeville/Mandelbrot-set-on-iPhone
import UIKit
extension CGRect {
init(_ x:CGFloat, _ y:CGFloat, _ w:CGFloat, _ h:CGFloat) {
self.init(x:x, y:y, width:w, height:h)
}
}
/// View that displays mandelbrot set
class MyMandelbrotView : UIView {
var bitmapContext: CGContext!
var odd = false
// the actor declaration puts us on the background thread
private actor MyMandelbrotCalculator {
private let MANDELBROT_STEPS = 200
func drawThatPuppy(center:CGPoint, bounds:CGRect) -> CGContext {
let bitmap = self.makeBitmapContext(size: bounds.size)
self.draw(center: center, bounds: bounds, zoom: 1, context: bitmap)
return bitmap
}
private func makeBitmapContext(size:CGSize) -> CGContext {
var bitmapBytesPerRow = Int(size.width * 4)
bitmapBytesPerRow += (16 - (bitmapBytesPerRow % 16)) % 16
let colorSpace = CGColorSpaceCreateDeviceRGB()
let prem = CGImageAlphaInfo.premultipliedLast.rawValue
let context = CGContext(data: nil, width: Int(size.width), height: Int(size.height), bitsPerComponent: 8, bytesPerRow: bitmapBytesPerRow, space: colorSpace, bitmapInfo: prem)
return context!
}
private func draw(center:CGPoint, bounds:CGRect, zoom:CGFloat, context:CGContext) {
func isInMandelbrotSet(_ re:Float, _ im:Float) -> Bool {
var fl = true
var (x, y, nx, ny) : (Float, Float, Float, Float) = (0,0,0,0)
for _ in 0 ..< MANDELBROT_STEPS {
nx = x*x - y*y + re
ny = 2*x*y + im
if nx*nx + ny*ny > 4 {
fl = false
break
}
x = nx
y = ny
}
return fl
}
context.setAllowsAntialiasing(false)
context.setFillColor(red: 0, green: 0, blue: 0, alpha: 1)
var re : CGFloat
var im : CGFloat
let maxi = Int(bounds.size.width)
let maxj = Int(bounds.size.height)
for i in 0 ..< maxi {
for j in 0 ..< maxj {
re = (CGFloat(i) - 1.33 * center.x) / 160
im = (CGFloat(j) - 1.0 * center.y) / 160
re /= zoom
im /= zoom
if (isInMandelbrotSet(Float(re), Float(im))) {
context.fill (CGRect(CGFloat(i), CGFloat(j), 1.0, 1.0))
}
}
}
}
}
private let calc = MyMandelbrotCalculator()
// jumping-off point: draw the Mandelbrot set
func drawThatPuppy() async {
let bounds = self.bounds
let center = CGPoint(x: bounds.midX, y: bounds.midY)
self.bitmapContext =
await self.calc.drawThatPuppy(center: center, bounds: bounds)
self.setNeedsDisplay()
}
// turn pixels of self.bitmapContext into CGImage, draw into ourselves
override func draw(_ rect: CGRect) {
if self.bitmapContext != nil {
let context = UIGraphicsGetCurrentContext()!
context.setFillColor(self.odd ? UIColor.red.cgColor : UIColor.green.cgColor)
self.odd.toggle()
context.fill(self.bounds)
let im = self.bitmapContext.makeImage()
context.draw(im!, in: self.bounds)
}
}
}
关于swift - 在后台线程中使用 async-await 有什么好处?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/75354030/
我有带皮肤的 DNN。我的 head 标签有 runat="server"所以我尝试在 head 标签内添加一个标签 "> 在后面的代码中,我在属性中设置了 var GoogleAPIkey。问题是它
我在 Node.JS 中有一个导出模块 exports.doSomethingImportant= function(req, res) { var id = req.params.id; Demo.
我是 F# 的新手,我一直在阅读 F# for Fun and Profit。在为什么使用 F#? 系列中,有一个 post描述异步代码。我遇到了 Async.StartChild函数,我不明白为什么
File 中有一堆相当方便的方法类,如 ReadAll***/WriteAll***/AppendAll***。 我遇到过很多情况,当我需要它们的异步对应物时,但它们根本不存在。 为什么?有什么陷阱吗
我最近开始做一个 Node 项目,并且一直在使用 async 库。我有点困惑哪个选项会更快。在某些数据上使用 async.map 并获取其结果,或使用 async.each 迭代一组用户并将他们的相应
您好,我正在试用 Springs 异步执行器,发现您可以使用 @Async。我想知道是否有可能在 @Async 中使用 @Async,要求是需要将任务委托(delegate)给 @Async 方法在第
我需要支持取消一个函数,该函数返回一个可以在启动后取消的对象。在我的例子中,requester 类位于我无法修改的第 3 方库中。 actor MyActor { ... func d
假设 asyncSendMsg不返回任何内容,我想在另一个异步块中启动它,但不等待它完成,这之间有什么区别: async { //(...async stuff...) for msg
我想用 Mocha 测试异步代码. 我跟着这个教程testing-promises-with-mocha .最后,它说最好的方法是 async/await。 以下是我的代码,我打算将 setTimeo
正如我有限(甚至错误)的理解,Async.StartImmediate 和 Async.RunSynchronously 在当前线程上启动异步计算。那么这两个功能究竟有什么区别呢?谁能帮忙解释一下?
我有一行使用await fetch() 的代码。我正在使用一些调用 eval("await fetch ...etc...") 的脚本注入(inject),但问题是 await 在执行时不会执行从ev
我正在尝试使用 nodeJS 构建一个网络抓取工具,它在网站的 HTML 中搜索图像,缓存图像源 URL,然后搜索最大尺寸的图像。 我遇到的问题是 deliverLargestImage() 在循环遍
我想结合使用 async.each 和 async.series,但得到了意想不到的结果。 async.each([1, 2], function(item, nloop) { async.s
我的代码有问题吗?我使用 async.eachSeries 但我的结果总是抛出 undefined。 这里是我的代码: async.eachSeries([1,2,3], function(data,
我想在 trait 中编写异步函数,但是因为 async fn in traits 还不被支持,我试图找到等效的方法接口(interface)。这是我在 Rust nightly (2019-01-0
async setMyPhotos() { const newPhotos = await Promise.all(newPhotoPromises); someOtherPromise();
async.js 中 async.each 与 async.every 的区别?似乎两者都相同,只是 async.every 返回结果。纠正我,我错了。 最佳答案 每个异步 .each(coll, i
我正在尝试对一组项目运行 async.each。 对于每个项目,我想运行一个 async.waterfall。请参阅下面的代码。 var ids = [1, 2]; async.each(ids,
我的目标是测试 API 调用,将延迟考虑在内。我的灵感来自 this post . 我设计了一个沙箱,其中模拟 API 需要 1000 毫秒来响应和更改全局变量 result 的值。测试检查 500
async.each 是否作为异步数组迭代工作? async.eachSeries 是否作为同步数组迭代工作?(它实际上等待响应) 我问这些是因为两者都有回调,但 async.each 的工作方式类似
我是一名优秀的程序员,十分优秀!