Alc
(Alc)
1
I am new to concurrency in Swift and I am trying to understand how to control the maximum number of concurrent tasks in a task group.
The following is a snippet I use to make concurrent requests. The specified endpoint returns a single integer after waiting (sleeping) for 1 second.
Expectation
Code takes ~1 second (excluding compilation time) total for requesting and retrieving 20 responses.
Actual
Code takes ~4 seconds and in the server, I can see it is being requested in batches of four. 6 + 6 + 6 + 2. This to me says that 6 is the max limit.
I want to understand how is this limit defined, and how I can increase / decrease this as I see fit.
Code
import Foundation
func makeRequests() async -> [Int] {
let url = URL(string: "http://localhost:8000")!
return await withTaskGroup(of: Int.self) {
g in
(0...20).forEach {
i in g.addTask {
try! await JSONDecoder().decode(Int.self, from: URLSession.shared.data(from: url).0)
}
}
return await g.reduce(into: []) { $0.append($1) }
}
}
print(await makeRequests())
My Effort
I did a bit of googling but I kept seeing references to DispatchQueue which from what I understand is supposed to be replaced by async / await? I also saw some (possibly roundabout) suggestions that involve fetching using next after reaching a certain limit, I guess this is fine if I want to rate limit it, but I am not sure how I can modify this approach to go over a certain limit (which is 6 in my case).
Apologies for the verboseness but I hope it explains my ask 
PS: I have confirmed my server can handle at least 20 concurrent requests. I used Python to make concurrent requests and I was able to make all of them in ~1 second. Just specifying this so that any questions regarding the server is not raised.
ibex10
2
Most likely this has something to do with the number of cpu cores on the machine where you are sending the requests from.
1 Like
Alc
(Alc)
3
Thank you, it seems I have 6 "performance" cores. If it's not too much to ask, can you direct me towards an approach that lets me override this limit? Should I still look into DispatchQueues or has newer alternatives emerged since?
I am fine with wanting to opt into a different limit under the assumption that it may lead to "thread explosions".
ibex10
4
I would just stick with the Swift task group, and let Swift's concurrency engine do its work. I don't believe you would gain anything if you were to be able to override the limit.
I am not an expert, so I would like to hear what @John_McCall would kindly say about this.
2 Likes
Jon_Shier
(Jon Shier)
5
This is the URLSession simultaneous request limit, not anything to do with Swift concurrency. You can try adjusting the limit by passing a custom URLSessionConfiguration but the system has an overall maximum you can’t exceed. If you want to test maximum concurrency parallelism, I suggest you do only local work.
3 Likes
Alc
(Alc)
6
I changed httpMaximumConnectionsPerHost in a custom config and I was able to get the output I expected. I also tried your other suggestion re: local work and I can confirm it works the way I expected it.
Thank you for both your suggestions.
jlukas
(Jacob Lukas)
7
You can also try using HTTP 2 or 3, which allow multiple simultaneous requests on a single connection.
2 Likes