English 中文(简体)
• 迅速等待/参加——如何 wait忙地等待完成“合成”任务?
原标题:Swift await/async - how to wait synchronously for an async task to complete?
问题回答

你们不应 wait忙地等待着一件好事。

One may come up with a solution similar to this:

func updateDatabase(_ asyncUpdateDatabase: @Sendable @escaping () async -> Void) {
    let semaphore = DispatchSemaphore(value: 0)

    Task {
        await asyncUpdateDatabase()
        semaphore.signal()
    }

    semaphore.wait()
}

虽然它在某些简单的条件下开展工作,但据

各种途径总是能够取得进展。

这意味着深处永远不会受阻。 如果法院的职能达到中止点(如等待表达),则该职能可以中止,但表面不会阻碍,它可以做其他工作。 根据这一合同,新的合作校对池只能够铺开许多路面,因为有CPU核心,避免过度的渗透环境变化。 这一合同也是造成僵局的关键原因。

上述情况违反了这一合同。 <代码>semaphore.wait()功能穿透。 这可能造成问题。 例如

func testGroup() {
    Task {
        await withTaskGroup(of: Void.self) { group in
            for _ in 0 ..< 100 {
                group.addTask {
                    syncFunc()
                }
            }
        }
        NSLog("Complete")
    }
}

func syncFunc() {
    let semaphore = DispatchSemaphore(value: 0)
    Task {
        try? await Task.sleep(nanoseconds: 1_000_000_000)
        semaphore.signal()
    }
    semaphore.wait()
}

Here we add 100 concurrent child tasks in the testGroup function, unfortunately the task group will never complete. In my Mac, the system spawns 4 cooperative threads, adding only 4 child tasks is enough to block all 4 threads indefinitely. Because after all 4 threads are blocked by the wait function, there is no more thread available to execute the inner task that signals the semaphore.

不安全使用的另一个例子是行为者的僵局:

func testActor() {
    Task {
        let d = Database()
        await d.updateSettings()
        NSLog("Complete")
    }
}

func updateDatabase(_ asyncUpdateDatabase: @Sendable @escaping () async -> Void) {
    let semaphore = DispatchSemaphore(value: 0)

    Task {
        await asyncUpdateDatabase()
        semaphore.signal()
    }

    semaphore.wait()
}

actor Database {
    func updateSettings() {
        updateDatabase {
            await self.updateUser()
        }
    }

    func updateUser() {

    }
}

此处称为<代码>更新功能将陷入僵局。 由于它等待了<代码>更新日期User的功能,而<代码>更新 用户功能与同一行为体隔绝,因此,它等待<代码>更新<<>> >。

以上两个例子使用<代码>DispadSemaphore。 同样,使用NS Conditions也是不安全的。 基本上等待同步,意味着阻挡目前的read。 避免这种模式,除非你只想临时解决办法并充分了解风险。

除使用ema光外,你还可以在以下网站完成你的日常工作:,如。 您可以发出信号,在基本任务完成后,使用wait UntilFinished(:

let op = TaskOperation {
   try await Task.sleep(nanoseconds: 1_000_000_000)
}
op.waitUntilFinished()

请注意,使用<代码>semaphore.wait()或op.wait UntilFinished( >,阻挡了目前对面的read,可能会造成现代一致的不确定的操作时间行为,因为现代一致假设所有线索都在不断取得进展。 如果你计划只在你不使用现代一致性的情况下使用这种方法,那么,如果你能够提供在不成熟的情况下无法使用的特性标识方法:

@available(*, noasync, message: "this method blocks thread use the async version instead")
func yourBlockingFunc() {
    // do work that can block thread
}

借助这一属性,你只能从非同化的角度援引这一方法。 但是,需要谨慎一些,因为如果这种方法没有具体规定<条码>不适用>。

页: 1 内容和用途

Task.synchronous { try await myAsyncFunc() }

利用这一简单延伸:

extension Task where Failure == Error {
    /// Performs an async task in a sync context.
    ///
    /// - Note: This function blocks the thread until the given operation is finished. The caller is responsible for managing multithreading.
    static func synchronous(priority: TaskPriority? = nil, operation: @escaping @Sendable () async throws -> Success) {
        let semaphore = DispatchSemaphore(value: 0)

        Task(priority: priority) {
            defer { semaphore.signal() }
            return try await operation()
        }

        semaphore.wait()
    }
}

这里是使用的一个例子:

func synchronousContext() { // ? No `async` keyword here

    let duration: UInt64 = 2_000_000_000 /* 2 seconds */
    var seconds: UInt64 { duration/1_000_000_000 }

    print("Start: Should wait for (seconds) seconds...")

    Task.synchronous { try await Task.sleep(nanoseconds: duration) } // ? No `await` keyword for calling the `Task.synchronous `

    print("...Ended after (seconds) seconds")
}

The following code can return a value from an async function using a function that is not async:

func performAsyncTask() -> Any? {
    class Enclosure {
        var value: Any?
    }
    
    let semaphore = DispatchSemaphore(value: 0)
    let enclosure = Enclosure()
    
    Task {
        enclosure.value = await yourAsyncFunction()
        semaphore.signal()
    }
    
    semaphore.wait()
    return enclosure.value
}

正如在其他答复中指出的那样,这将阻碍目前的工作,直到完成“合成”的任务,因此,你应当能够理解风险并谨慎行事。





相关问题
SwiftUI: How do I position a button x points above a sheet?

I am trying to recreate a Maps-style UI with a persistent bottom sheet and controls fixed above. Apple Maps UI with controls above ☝️ Example here, the "Look Around" binoculars button and ...

BraintreeDropIn deprecated functions error

I m getting this error on the latest release of BraintreeDropIn, I really don t get it since based on the patch notes, this should ve been addressed already, I have already tried cleaning derived data,...

how to limit zoom level in map swift ui?

how to limit zoom level in map swift ui i have map and need to make zoom level limited Map(coordinateRegion: $region,annotationItems: viewModel.nearbyGyms) { item in ...

UIImageView - How to get the file name of the image assigned?

Is it possible to read the name of an UIImageView s UIImage that s presently stored in the UIImageView? I was hoping you could do something kind of like this, but haven t figured it out. NSString *...