Reputation: 1583
I need a bit of help on proper for loop multithreading for swift 4. Should I use a normal dispatch queue or should I use concurrent threading? Or am I thinking about this wrong? The specific instance I am looking at here is: say we want to do something to a list of objects, such as retrieve a user picture from a database for all users that are missing one in a local database on the device.
let utilityQueue = DispatchQueue(label: "com.company.utility", qos: .utility)
for i in 1 ... 10000 {
utilityQueue.async {
getMissingImage(user[i])
}
}
The above seems to work for me, but I found another option in my reading, but using concurrency such as below
let concurrentQueue = DispatchQueue(label: "com.company.concurrent", attribute: .concurrent)
for i in 1 ... 10000 {
concurrentQueue.async {
getMissingImage(user[i])
}
}
Which is correct or is there a better way to handle this that I am missing?
Upvotes: 1
Views: 2346
Reputation: 437432
The attempt to start an unconstrained number of concurrent tasks, is dangerous, because GCD has a very limited number of worker threads and if you exhaust them, you can adversely impact other operations within the app.
So consider your example:
let concurrentQueue = DispatchQueue(label: "com.company.concurrent", attributes: .concurrent)
for i in 0 ..< 10_000 {
concurrentQueue.async {
self.getMissingImage(self.user[i])
}
}
You might use OperationQueue
which lets you easily constrain the degree of concurrency, in this example not more than 4 at a time:
let queue = OperationQueue()
queue.name = "com.company.concurrent"
queue.qualityOfService = .userInitiated
queue.maxConcurrentOperationCount = 4
for i in 0 ..< 10_000 {
queue.addOperation {
self.getMissingImage(self.user[i])
}
}
You can accomplish something similar with GCD semaphores, but it’s a little more fragile and I’d suggest the above.
Note, this assumes that getMissingImage
runs synchronously (i.e. will not return until the task is completely done). If not, you’ll have to pursue other patterns.
Upvotes: 1