Executing blocking code in async/await

Hello guys,

Do you know what's the most idiomatic way to offload blocking code to the separate thread or thread pool and get asynchronous function back? I'm looking at equivalent of spawn_blocking from Rust's tokio create. It's important that this method should work also for Linux and Windows.

Something like this:

func spawnBlocking<T>(_ execute: @escaping () -> T) async -> T {
    await withCheckedContinuation { continuation in
        DispatchQueue.global().async {
            continuation.resume(returning: execute())
        }
    }
}

and if the function to execute is throwing:

func spawnBlocking<T>(_ execute: @escaping () throws -> T) async throws -> T {
    try await withCheckedThrowingContinuation { continuation in
        DispatchQueue.global().async {
            continuation.resume(with: Result(catching: execute))
        }
    }
}
3 Likes

Thank you for the response!

Thank you, @tera

But, why does the following code return (Function), not the expected numeric result of the computation?

@main
import Foundation

@main
enum AsyncAwaitBlockingCode {
    static func main () async throws {
        async let u = spawnBlocking {
            {() in 17 + 19}
        }
        
        await print ("-->", u, u ())
        
        async let v = spawnBlocking_throws {
            {() in 23 + 29}
        }
        
        try await print ("-->", v, v ())
    }
}

func spawnBlocking<T>(_ execute: @escaping () -> T) async -> T {
    await withCheckedContinuation { continuation in
        DispatchQueue.global().async {
            continuation.resume(returning: execute())
        }
    }
}

func spawnBlocking_throws <T>(_ execute: @escaping () throws -> T) async throws -> T {
    try await withCheckedThrowingContinuation { continuation in
        DispatchQueue.global().async {
            continuation.resume(with: Result(catching: execute))
        }
    }
}


--> (Function) 36
--> (Function) 52

You have a nested closure, is that on purpose? If I got the intention right you want this:

        async let u = spawnBlocking { 17 + 19 }
        await print ("-->", u)
        async let v = spawnBlockingThrows { 23 + 29 }
        try await print ("-->", v)

Oops. :face_with_open_eyes_and_hand_over_mouth:

Thank you, @tera