Swift异步等待任务组中的所有任务

axkjgtzd  于 2023-08-02  发布在  Swift
关注(0)|答案(1)|浏览(164)

我正在使用一个任务组来 Package 对一个长时间运行的异步方法的重复调用。由于我可能有许多需要发生的对该方法的调用,因此希望它们能够并行运行。在一天结束的时候,我有一些常规的同步代码,需要阻塞,直到所有这些异步被调用。
奇怪的是,与我见过的其他任务组示例不同,我实际上不需要async throws方法的值。它们执行操作并将其写入磁盘。
有没有办法清理这个代码?

let swiftAsyncSemaphor = DispatchSemaphore(value: 0)
let taskGroupTask = Task {
    await withThrowingTaskGroup(of: ASRJob.self) { group in
        for path in filePathsToWorkOn {
            group.addTask {
                return try await doHardWork(atPath: path)
            }
        }
        
        do {
            for try await _ in group {
                // For now we do not store this information
            }
        } catch {
            // For now we do not store the error
        }
    }
    swiftAsyncSemaphor.signal()
}
swiftAsyncSemaphor.wait()

字符串
我看到的大多数例子都在组的末尾使用了map/合并函数,但我不需要数据,所以我怎么能等待它们全部完成呢?
运行此代码的上下文:此代码在同步操作(NSOperation)的main()块中运行,该同步操作位于OperationQueue中。所以调用wait的块不是在swift异步代码中。目标是阻止操作完成,直到这个快速异步工作完成,知道它可能会运行很长一段时间。

hec6srdp

hec6srdp1#

如果您在异步上下文中使用semaphore.wait(),它将产生以下警告:
示例方法“wait”在异步上下文中不可用;等待任务句柄;这是Swift 6中的错误
我假设您必须在异步上下文之外等待这个信号量,否则它将产生上面的警告。
不能在async-await任务之间结合使用依赖项的信号量。参见Swift concurrency: Behind the scenes
[原始]像旗语...在Swift并发中使用不安全。这是因为它们隐藏了Swift运行时的依赖信息,但在代码执行中引入了依赖。由于运行时不知道此依赖项,因此它无法做出正确的调度决策并解决这些决策。特别是,不要使用创建非结构化任务的原语,然后通过使用信号量或不安全的原语追溯性地引入跨任务边界的依赖关系。这样的代码模式意味着一个线程可以无限期地阻塞信号量,直到另一个线程能够解除阻塞。这违反了线程向前进度的运行时契约。
async方法中的模式是await任务组的result

let task = Task {
    try await withThrowingTaskGroup(of: ASRJob.self) { group in
        for path in filePathsToWorkOn {
            group.addTask {
                try await doHardWork(atPath: path)
            }
        }

        try await group.waitForAll()
    }
}

_ = await task.result

字符串
对于抛出任务组,我们也经常会waitForAll
是的,从技术上讲,您可以在Operation中使用wait,但即使这样也是一种反模式。我们通常会写一个“并发”操作。参见Operationdocumentation中关于“并发操作”的讨论。Trying to Understand Asynchronous Operation Subclass

相关问题