Post not yet marked as solved
In my TestApp I run the following code, to calculate every pixel of a bitmap concurrently:
private func generate() async {
for x in 0 ..< bitmap.width{
for y in 0 ..< bitmap.height{
let result = await Task.detached(priority:.userInitiated){
return iterate(x,y)
}.value
displayResult(result)
}
}
}
This works and does not give any warnings or runtime issues.
After watching the WWDC talk "Visualize and optimize Swift concurrency" I used instruments to visualize the Tasks:
The number of active tasks continuously raises until 2740 and stays constant at this value even after all 64000 pixels have been calculated and displayed.
What am I doing wrong?
Post not yet marked as solved
I have a Networking client that contains some shared mutable state. I decided to make this class an actor to synchronize access to this state. Since it's a networking client, it needs to make calls into URLSession's async data functions.
struct MiddlewareManager {
var middleware: [Middleware] = []
func finalRequest(for request: URLRequest) -> URLRequest { ... }
}
actor Networking {
var middleware = MiddlewareManager()
var session: URLSession
func data(from request: URLRequest) async throws -> (Data, URLResponse) {
let finalRequest = middleware.finalRequest(for: request)
let (data, response) = try await session.data(for: finalRequest)
let finalResponse = middleware.finalResponse(for: response)
// ...
return (data, finalResponse)
}
}
Making a network request could be a long running operation. From my understanding long running or blocking operations should be avoided inside of actors. I'm pretty sure this is non blocking due to the await call, the task just becomes suspended and the thread continues on, but it will inherit the actor's context. As long URLSession creates a new child task then this is ok, since the request isn't actually running on the actor's task?
My alternative approach after watching the tagged WWDC 2022 videos was to add the nonisolated tag to the function call to allow the task to not inherit the actor context, and only go to the actor when needed:
nonisolated func data(from request: URLRequest) async throws -> (Data, URLResponse) {
let finalRequest = await middleware.finalRequest(for: request)
let (data, response) = try await session.data(for: finalRequest)
let finalResponse = await middleware.finalResponse(for: response)
// ...
return (data, finalResponse)
}
Is this the proper or more correct way to solve this?