Swift - async/await - 如何从MainActor任务中执行异步方法到后台线程

4

这是我的viewDidLoad方法:

func viewDidLoad() {
    // Stuff here
    Task { @MainActor in 
        doSomeWorkOnMainThread1()
        doSomeWorkOnMainThread2()

        await doSomeBackgroundWork()

        doSomeWorkOnMainThread3()
        doSomeWorkOnMainThread4()
    }
}

以下是我的方法,应该可以在后台线程上执行工作:

func doSomeBackgroundWork() async {
    // can add some code here
    // long image processing task
    assert(!Thread.isMainThread)
    // can add some code here
}

是否可以在后台线程上执行doSomeBackgroundWork(不使用GCD),并在返回主线程之前等待它?


“我想要”只是一种愿望,而不是问题(而且是相当模糊的愿望)。实际的问题/难题是什么?你已经绘制了代码,那么它的问题在哪里?谢谢。 - matt
顺便说一下,我建议不要像那样使用@MainActor。确保方法在主actor上运行的方法是将该方法标记为@MainActor - matt
谢谢,我已经编辑了我的问题* - Xys
如果我在方法中添加@MainActor,我会得到这个错误:'async' call in a function that does not support concurrency - Xys
好的,那会是个单独的问题。:) 但我的观点是,我认为你不能轻易地保证从后台任务返回后仍然在主线程上,除非 doSomeWorkOnMainThread3 本身就是一个主角色方法。当然我可能是错的,但这是我的经验。 - matt
1
尝试使用分离的任务。 - valeCocoa
2个回答

1

你正在寻找Task.sleep。请注意它的单位是纳秒,这很奇怪,因此我编写了一个扩展来切换到秒;要使用它,必须使用Double而不是Int:

extension Task where Success == Never, Failure == Never {
    static func sleep(_ seconds:Double) async {
        await self.sleep(UInt64(seconds * 1_000_000_000))
    }
    static func sleepThrowing(_ seconds:Double) async throws {
        try await self.sleep(nanoseconds: UInt64(seconds * 1_000_000_000))
    }
}

保证一个工作在后台线程中完成的方法是将该工作交给Actor。这也是Actor的部分作用。

例如,如果一个Actor有一个名为doSleep的方法调用Task.sleep,那么如果你实例化该Actor并从你的任务中调用该方法,它将在后台线程上睡眠。


如果我的表述不够清晰,那是我的错。sleep 只是一个例子,我实际上并没有在后台线程上执行 sleep,而是在进行需要时间的实际工作。 - Xys
我不知道你在干什么。我已经告诉过你该怎么做了,你还需要什么? - matt
1
你有没有看过我关于这个主题的文章?它可能会有所帮助:https://www.biteinteractive.com/swift-5-5-replacing-gcd-with-async-await/ - matt
@Rob 实际上我不知道。他们在这方面做了什么更改?并且在哪个版本的Xcode中进行了更改? - matt
我认为提供基于秒的版本的扩展是有用的。我的观点仅仅是你的非抛出版本正在调用一个已弃用的方法,应该被移除或修复。(个人而言,我会直接删除非抛出版本并重命名抛出版本,但这取决于你。) - Rob
显示剩余8条评论

-2

这个解决方案可以工作,但我猜并不完美:

func doSomeBackgroundWork() async {
    await Task {
        // long image processing task
        assert(!Thread.isMainThread)
    }.result
}

这没问题,但除非它是Actor方法,否则不能保证后台执行,就像我已经告诉过你的那样。 - matt
你在哪里看到默认的Task可以在主线程上运行?它是否写在官方文档中? - Xys

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接