标签: swift-concurrency

使 Actor 符合 Sequence 协议

如何让参与者遵守协议Sequence?以下代码生成编译器警告:

与全局参与者“MainActor”隔离的实例方法“makeIterator()”无法满足协议“Sequence”的相应要求

@MainActor class Test: Sequence {
    private var contents: [Int] = []
    
    func makeIterator() -> Array<Int>.Iterator {
        contents.makeIterator()
    }
}
Run Code Online (Sandbox Code Playgroud)

concurrency swift swift-concurrency

3
推荐指数
1
解决办法
3252
查看次数

如何制作异步 Swift 函数“@synchronized”?

我想创建一个异步函数,它本身使用异步调用。我还想确保在任何时刻只有一个呼叫被主动处理。所以我想要一个async @synchronized函数。

怎么做?将函数体包装在 内并dispatchQueue.sync {}不能像它期望的同步代码那样工作。另外,似乎DispatchQueue一般不设计有要执行的异步代码块/任务。

该代码与硬件通信,因此本质上是异步的,这就是为什么我想要为我的库提供异步接口。(我不想在通信阶段发生时阻止应用程序。)但是某些操作无法在硬件上并行执行,因此我必须进行同步,以便某些操作不会同时发生。

synchronization async-await swift swift-concurrency

3
推荐指数
1
解决办法
2873
查看次数

多个分离任务不会同时执行

class ViewModel: ObservableObject { }

struct ContentView: View {
    @StateObject private var model = ViewModel()

    var body: some View {
        Button("Authenticate", action: doWork)
    }

    func doWork() {
        Task.detached {
            for i in 1...10_000 {
                print("In Task 1: \(i)")
            }
        }

        Task.detached {
            for i in 1...10_000 {
                print("In Task 2: \(i)")
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这是https://www.hackingwithswift.com/quick-start/concurrency/whats-the-difference- Between-a-task-and-a-detached-task 中描述的代码。

由于 doWork 中的任务是分离的,我希望它们同时执行。上面的文章也是这么说的。

但是,当我运行它时,Task2 在 Task1 之后执行。
我错了吗?

swift swift-concurrency

3
推荐指数
1
解决办法
520
查看次数

将 async/await (Swift 5.5) 与 firebase 实时数据库结合使用

我使用 firebase 的实时数据库从我的应用程序进行异步数据库查询。现在 iOS 15 为我们提供了 Swift 5.5,我喜欢使用async/await来执行这些查询,而不是传递完成闭包。

我知道我可以使用await withCheckedThrowingContinuation { }现有的 firebase 函数构建异步版本。但是异步版本已经存在吗?在 firebase 中还是由 Xcode 自动合成?

async-await firebase swift firebase-realtime-database swift-concurrency

2
推荐指数
1
解决办法
915
查看次数

Swift 并发 UIButton

是否可以在 UIKit 中使用 async/await 进行 POST HTTP 请求,即 from UIButton

我可以发送请求,但它立即崩溃。完美地使用URLSession,并以此作为学习经验。

lazy var buttonTest: UIButton = {
    let button = UIButton()
    button.addTarget(self, action: #selector(testAsyncTwo), for: .touchUpInside)
    return button
}()

@objc func testAsync() async throws {
    let date = Date()
    let df = DateFormatter()
    df.dateFormat = "yyyy-MM-dd HH:mm:ss"
    let dateString = df.string(from: date)

    let json: [String: Any] = ["item": "1",
                               "time": "\(dateString)"]
    let jsonData = try? JSONSerialization.data(withJSONObject: json)
    
    guard let url = URL(string: "https://myapiendpoint.com/api/") else { fatalError("Missing URL") …
Run Code Online (Sandbox Code Playgroud)

uikit async-await swift swift-concurrency

2
推荐指数
1
解决办法
1454
查看次数

在 Swift 代码中任务似乎总是按顺序运行

这段代码似乎总是像魔术一样工作。没有任何锁定,输出为 1,2。

class Counter {
    var count = 0
    func increment() -> Int {
        count += 1
        return count
    }
}

class ViewController: UIViewController {
    
    var tasks = [Task<Void, Never>]()

    override func viewDidLoad() {
        super.viewDidLoad()
        
        let counter = Counter()
        
        tasks += [
            Task.detached {
                print(counter.increment())
            }
        ]

        tasks += [
            Task.detached {
                print(counter.increment())
            }
        ]
    }
}
Run Code Online (Sandbox Code Playgroud)

此代码来自https://www.andyibanez.com/posts/understanding-actors-in-the-new-concurrency-model-in-swift/

我预计它会不一致地工作。我尝试将其切换为不使用分离任务,但它仍然总是返回 1,2。到底是怎么回事?

swift swift-concurrency

1
推荐指数
1
解决办法
486
查看次数

Swift 并发任务与调度队列线程:什么决定了同时运行的任务数量?

对于这个 swift 游乐场(查看 swiftfiddle或以下),我有三个流程密集型工作循环。使用线程的线程会产生 50 个线程,所有线程一起工作(通过最后报告的循环数量的增加来显示),而具有并发性的线程只会同时执行两个任务。什么决定了要在其中运行任务的线程数?正如我在评论中提到的,一种方法不一定比另一种方法更快,因为 50 个线程竞争资源远非理想,但 2 似乎是一个非常低的数字。

import PlaygroundSupport
import UIKit

PlaygroundPage.current.needsIndefiniteExecution = true

func asyncProcess(_ this:Int) async{
    print("   async -- starting \(this)")
    let x = Int.random(in: 1000...10000000)
    await withUnsafeContinuation{
        for _ in 1..<x {}
        $0.resume()
    }
    print("   async -- ending \(this) after \(x) times")
}

func threadedProcess(_ this:Int) {
    print("threaded -- starting \(this) on \(Thread.current)")
    let x = Int.random(in: 1000...10000000)
    for _ in 1..<x {}
    print("threaded -- ending \(this) after \(x) times on \(Thread.current)") …
Run Code Online (Sandbox Code Playgroud)

multithreading swift dispatch-queue swift-concurrency

1
推荐指数
1
解决办法
1634
查看次数

将异步抛出表达式转换为结果

根据保留抛出表达式的结果文档,可以将抛出表达式转换为Result类型,如下所示:

let singleSample = Result { try UnreliableRandomGenerator().random() }
Run Code Online (Sandbox Code Playgroud)

是否也可以将async抛出表达式转换为Result如下类型:

let singleSample = Result { try await UnreliableRandomGenerator().random() } 
Run Code Online (Sandbox Code Playgroud)

swift swift-concurrency

1
推荐指数
1
解决办法
625
查看次数

我是否应该在“MainActor”视图模型中声明“非隔离”或“异步”函数,以便在 MainActor 上下文内部和外部运行?

介绍

我有一个视图模型声明如下:

@MainActor class ContentViewModel: ObservableObject {
    ...
}
Run Code Online (Sandbox Code Playgroud)

我想向该模型添加一个函数,该函数在MainActor上下文内部和外部混合执行工作。

我进行了一些实验,并提出了两个实现此目的的选项,如下所述。

选项1

在视图模型中将新函数标记为nonisolated并在该函数内启动一个任务,如下所示:

nonisolated func someFunction() {
    Task {
        // Do work here.
        // Use 'await' to make calls to the 'MainActor' context
        // and to make other asynchronous calls.
    }
}
Run Code Online (Sandbox Code Playgroud)

在视图中调用该函数如下:

Button("Execute") {
    viewModel.someFunction()
}
Run Code Online (Sandbox Code Playgroud)

选项2

在视图模型中将新函数标记为async并省略任务启动,如下所示:

func someFunction() async {
    // Do work here.
    // No need to 'await' to make calls to the 'MainActor' context
    // given …
Run Code Online (Sandbox Code Playgroud)

swift swiftui swift-concurrency

1
推荐指数
1
解决办法
916
查看次数

actor方法可以并发交互吗?

我正在观看有关使用 Swift Actor 保护可变状态的WWDC 视频

在一个示例中,他们展示了如何同时调用参与者方法

想象一下,我们有两个不同的并发任务试图同时获取相同的图像。第一个发现没有缓存条目,开始从服务器下载图像,然后被挂起,因为下载需要一段时间。当第一个任务是下载映像时,新映像可能会部署到同一 URL 下的服务器。现在,第二个并发任务尝试获取该 URL 下的图像。它还看不到缓存条目,因为第一次下载尚未完成,然后开始图像的第二次下载。下载完成时它也会被暂停。一段时间后,其中一个下载(假设这是第一个下载)将完成,并且其任务将在 Actor 上恢复执行。它填充缓存并返回猫的结果图像。现在第二个任务已完成下载,因此它被唤醒。它用它得到的悲伤猫的图像覆盖缓存中的相同条目。因此,即使缓存中已经填充了图像,我们现在也会为同一 URL 获取不同的图像。

在此输入图像描述

Actor 的整个想法不就是确保在任何给定时间只有一个调用者可以直接与 Actor 交互吗?

这是我的例子。在这里您可以看到“BEGIN增量”后面始终跟着“END增量”,并且后续调用increment必须等待

actor Counter {
    var count = 1

    func increment() {
        print("BEGIN increment")
        let url = URL(string: "https://google.com")!
        let data = try! Data(contentsOf: url)
        let string = String(data: data, encoding: .utf8) ?? ""
        print("END increment")
        count += 1
    }
}


struct ContentView: View {
    @State var counter = Counter()

    var body: some View {
        Button {
            Task.detached { …
Run Code Online (Sandbox Code Playgroud)

actor async-await swift swift-concurrency

0
推荐指数
1
解决办法
336
查看次数