2

Swift Concurrency 文档提供了以下示例,说明如何并行等待多个异步函数。

async let firstPhoto = downloadPhoto(named: photoNames[0])
async let secondPhoto = downloadPhoto(named: photoNames[1])
async let thirdPhoto = downloadPhoto(named: photoNames[2])

let photos = await [firstPhoto, secondPhoto, thirdPhoto]

有没有办法并行等待任意数量的异步函数?我尝试了下面代码中显示的方法,但找不到使其工作的方法。

var photoPromises: [PhotoPromise] = []
for name in photoNames {
    photoPromises.append(downloadPhoto(named: name))
}
let photos = await photoPromises
4

2 回答 2

0

是的,你有正确的想法。我在这里发现了一个类似的问题:

尝试使用 when 语句来等待已履行的承诺:


when(fulfilled: promiseArray).then { results in
    // Do something
}.catch { error in
    // Handle error
}

这是原始问题,但那里引用的链接已损坏。

Swift & PromiseKit:从循环中解决所有的承诺

于 2022-01-05T20:33:50.350 回答
0
import UIKit
import XCTest

struct Downloader
{
    static func download(photoURLs: [URL]) async throws -> [UIImage] {
        try await withThrowingTaskGroup(of: UIImage.self) { group in
            var collected = [UIImage]()
            for url in photoURLs {
                group.addTask {
                    let (data, _) = try await URLSession.shared.data(from: url)
                    return UIImage(data: data)!
                }
            }
            for try await value in group {
                collected.append(value)
            }
            return collected
        }
    }
}

final class PhotosTests: XCTestCase
{
    func testDownloader() async throws {
        let images = try await Downloader.download(photoURLs: [
            URL(string: "https://placekitten.com/200/300")!,
            URL(string: "https://placekitten.com/g/200/300")!
        ])
        XCTAssertNotNil(images[0])
        XCTAssertNotNil(images[1])
        XCTAssertEqual(images.count, 2)
    }
}

通用 map/reduce 版本

import UIKit
import XCTest

struct MapReduce
{
    static func mapReduce<T,U>(inputs: [T], process: @escaping (T) async throws -> U ) async throws -> [U] {
        try await withThrowingTaskGroup(of: U.self) { group in
            // map
            for input in inputs {
                group.addTask {
                    try await process(input)
                }
            }
            // reduce
            var collected = [U]()
            for try await value in group {
                collected.append(value)
            }
            return collected
        }
    }
}

final class PhotosTests: XCTestCase
{
    func testDownloader() async throws {
        let input = [
            URL(string: "https://placekitten.com/200/300")!,
            URL(string: "https://placekitten.com/g/200/300")!
        ]
        let download: (URL) async throws -> UIImage = { url in
            let (data, _) = try await URLSession.shared.data(from: url)
            return UIImage(data: data)!
        }
        let images = try await MapReduce.mapReduce(inputs: input, process: download)
        XCTAssertNotNil(images[0])
        XCTAssertNotNil(images[1])
        XCTAssertEqual(images.count, 2)
    }
}
于 2022-01-07T11:27:08.913 回答