DispatchSemaphore + DispatchQueue not working as expected? - ios

I'm trying to improve the time it takes for a task to finish by leveraging multithreading/paralleling.
I'm reading CMSampleBuffers from a video track, manipulating them, then storing them back to an array for later use. Because each manipulation is "costly" in terms of RAM and CPU, I'm using DispatchSemaphore to limit the number of parallel tasks (5 in the example).
Basically, I'm trying to make the "system" process more than a single frame in a time, and not above 5 so the device won't crash due to memory issues. In the current implementation below it's for some reason doing it almost serialize and not in parallel.
Any help will be highly appreciated!
I tried taking reference from here: How to limit gcd queue buffer size for the implementation.
Code:
class MyService {
let semaphore = DispatchSemaphore(value: 5)
let processQueue = DispatchQueue(label: "custom.process", attributes: .concurrent)
func startReading() {
for sampleBuffer in sampleBuffers {
// signal wait
semaphore.wait()
// async queue
processQueue.async {
// run taks
self.process(buffer: sampleBuffer) { pixelBuffer in
// singal to semaphore
self.semaphore.signal()
}
}
}
}
func process(buffer: CMSampleBuffer, completion: #escaping (CVPixelBuffer) -> (Void)) {
// run on a background thread to avoid UI freeze
DispatchQueue.global(qos: .userInteractive).async {
// Do something
// Do something
// Do something
// Do something
completion(processedBuffer)
}
}
}

Related

Swift: How to wait for an asynchronous, #escaping closure (inline)

How is it possible to wait for an #escaping closure to complete inline before proceeding?
I am utilizing the write method from AVSpeechSynthesizer, which uses an #escaping closure, so the initial AVAudioBuffer from the callback will return after createSpeechToBuffer has completed.
func write(_ utterance: AVSpeechUtterance, toBufferCallback bufferCallback: #escaping AVSpeechSynthesizer.BufferCallback)
My method writes speech to a buffer, then resamples and manipulates the output, for a workflow, where speech is done in faster than real-time.
The goal is to perform the task inline, to avoid changing the workflow to standby for the 'didFinish' delegate
speechSynthesizer(_ synthesizer: AVSpeechSynthesizer, didFinish utterance: AVSpeechUtterance)
I believe this question can be generalized to dealing with #escaping closures within a function\method
import Cocoa
import AVFoundation
let _speechSynth = AVSpeechSynthesizer()
func resampleBuffer( inSource: AVAudioPCMBuffer, newSampleRate: Float) -> AVAudioPCMBuffer
{
// simulate resample data here
let testCapacity = 1024
let audioFormat = AVAudioFormat(standardFormatWithSampleRate: Double(newSampleRate), channels: 2)
let simulateResample = AVAudioPCMBuffer(pcmFormat: audioFormat!, frameCapacity: UInt32(testCapacity))
return simulateResample!
}
func createSpeechToBuffer( stringToSpeak: String, sampleRate: Float) -> AVAudioPCMBuffer?
{
var outBuffer : AVAudioPCMBuffer? = nil
let utterance = AVSpeechUtterance(string: stringToSpeak)
var speechIsBusy = true
utterance.voice = AVSpeechSynthesisVoice(language: "en-us")
let semaphore = DispatchSemaphore(value: 0)
_speechSynth.write(utterance) { (buffer: AVAudioBuffer) in
guard let pcmBuffer = buffer as? AVAudioPCMBuffer else {
fatalError("unknown buffer type: \(buffer)")
}
if ( pcmBuffer.frameLength == 0 ) {
print("buffer is empty")
} else {
print("buffer has content \(buffer)")
}
outBuffer = resampleBuffer( inSource: pcmBuffer, newSampleRate: sampleRate)
speechIsBusy = false
// semaphore.signal()
}
// wait for completion of func speechSynthesizer(_ synthesizer: AVSpeechSynthesizer, didFinish utterance: AVSpeechUtterance)
// while ( _speechSynth.isSpeaking )
// {
// /* arbitrary task waiting for write to complete */
// }
//
// while ( speechIsBusy )
// {
// /* arbitrary task waiting for write to complete */
// }
// semaphore.wait()
return outBuffer
}
print("SUCCESS is waiting, returning the non-nil output from the resampleBuffer method.")
for indx in 1...10
{
let sentence = "This is sentence number \(indx). [[slnc 3000]] \n"
let outBuffer = createSpeechToBuffer( stringToSpeak: sentence, sampleRate: 48000.0)
print("outBuffer: \(String(describing: outBuffer))")
}
After I wrote the createSpeechToBuffer method and it failed to produce the desired output (inline), I realized that it returns before getting the results of the resampling. The callback is escaping, so the initial AVAudioBuffer from the callback will return after createSpeechToBuffer has completed. The actual resampling does work, however I currently must save the result and continue after being notified by the delegate "didFinish utterance" to proceed.
Attempts at waiting for _speechSynth.isSpeaking, speechIsBusy flag, dispatch queue and semaphore are blocking the write method (using _speechSynth.write) from completing.
How is it possible to wait for the result inline versus recreating a workflow depending on the delegate "didFinish utterance"?
I'm on macOS 11.4 (Big Sur) but I believe this question is applicable to macOS and ios
It looks to me that the commented-out code for DispatchSemaphore would work if the #escaping closure is run concurrently, and I think the problem is that it is run serially, or more accurately, not run at all, because it is scheduled to run serially. I'm not specifically familiar with the AVSpeechSynthesizer API, but from your description, it sounds to me as though it's calling on the main dispatch queue, which is a serial queue. You call wait to block until _speechSynth.write completes, but that's blocking the main thread, which prevents it from ever continuing to the next iteration of the run loop, so the actual work of _speechSynth.write never even starts.
Let's back up. Somewhere behind the scenes your closure is almost certainly called via DispatchQueue.main's async method, either because that's where speechSynth.write does its work then calls your closure synchronously on the current thread at the time, or because it explicitly calls it on the main thread.
A lot of programmers are sometimes confused as to exactly what async does. All async means is "schedule this task and return control to the caller immediately". That's it. It does not mean that the task will be run concurrently, only that it will be run later. Whether it is run concurrently or serially is an attribute of the DispatchQueue whose async method is being called. Concurrent queues spin up threads for their tasks, which either can be run in parallel on different CPU cores (true concurrency), or interleaved with the current thread on the same core (preemptive multitasking). Serial queues on the other hand have a run loop as in NSRunLoop, and run their scheduled tasks synchronously after dequeuing them.
To illustrate what I mean, the main run loop looks vaguely like this, and other run loops are similar:
while !quit
{
if an event is waiting {
dispatch the event <-- Your code is likely blocking in here
}
else if a task is waiting in the queue
{
dequeue the task
execute the task <-- Your closure would be run here
}
else if a timer has expired {
run timer task
}
else if some view needs updating {
call the view's draw(rect:) method
}
else { probably other things I'm forgetting }
}
createSpeechToBuffer is almost certainly being run in response to some event processing, which means that when it blocks, it does not return back to the run loop to continue to the next iteration where it checks for tasks in the queue... which from the behavior you describe, seems to include the work being done by _speechSynth.write... the very thing you're waiting for.
You can try explicitly creating a .concurrent DispatchQueue and using it to wrap the call to _speechSynth.write in an explicit async call, but that probably won't work, and even if it does, it will be fragile to changes Apple might make to AVSpeechSynthesizer's implementation.
The safe way is to not block... but that means re-thinking your work flow a little. Basically whatever code would be called after createSpeechToBuffer returns should be called at the end of your closure. Of course, as currently written createSpeechToBuffer doesn't know what that code is (nor should it). The solution is to inject it as a parameter... meaning createSpeechToBuffer itself would also take an #escaping closure. And of course, that means it can't return the buffer, but instead passes it to the closure.
func createSpeechToBuffer(
stringToSpeak: String,
sampleRate: Float,
onCompletion: #escaping (AVAudioPCMBuffer?) -> Void)
{
let utterance = AVSpeechUtterance(string: stringToSpeak)
utterance.voice = AVSpeechSynthesisVoice(language: "en-us")
let semaphore = DispatchSemaphore(value: 0)
_speechSynth.write(utterance) { (buffer: AVAudioBuffer) in
guard let pcmBuffer = buffer as? AVAudioPCMBuffer else {
fatalError("unknown buffer type: \(buffer)")
}
if ( pcmBuffer.frameLength == 0 ) {
print("buffer is empty")
} else {
print("buffer has content \(buffer)")
}
onCompletion(
resampleBuffer(
inSource: pcmBuffer,
newSampleRate: sampleRate
)
)
}
}
If you really want to maintain the existing API, the other approach is to move the entire workflow itself to a .concurrent DispatchQueue, which you can block to your heart's content without worry that it will block the main thread. AVSpeechSynthesizer could schedule its work wherever it likes without a problem.
If using Swift 5.5 is an option, you might look into its async and await keywords. The compiler enforces a proper async context for them so that you don't block the main thread.
Update to answer how to call my version.
Let's say your code that calls createSpeechToBuffer currently looks like this:
guard let buffer = createSpeechToBuffer(stringToSpeak: "Hello", sampleRate: sampleRate)
else { fatalError("Could not create speechBuffer") }
doSomethingWithSpeechBuffer(buffer)
You'd call the new version like this:
createSpeechToBuffer(stringToSpeak: "Hello", sampleRate: sampleRate)
{
guard let buffer = $0 else {
fatalError("Could not create speechBuffer")
}
doSomethingWithSpeechBuffer(buffer)
}

How to get swift operation synced one after other using serial or concurrent queue in GCD?

I'm trying to fiddle with concurrent/serial queues and sync/async operations and came across a scenario which I'm not able to solve. Would be glad if someone can assist.
So it goes like this -
I have a queue and I'm trying to simulate an async image download operation by using asynAfter, and I'm able to get below result by this code.
var downloadQueue = DispatchQueue(label: "com.image.download", attributes: .concurrent)
var operation1 = {
downloadQueue.asyncAfter(deadline: DispatchTime.now() + 6.0) {
print("Image Download 1 Done")
}
}
var operation2 = {
downloadQueue.asyncAfter(deadline: DispatchTime.now() + 4.0) {
print("Image Download 2 Done")
}
}
var operation3 = {
downloadQueue.asyncAfter(deadline: DispatchTime.now() + 2.0) {
print("Image Download 3 Done")
}
}
operation1()
operation2()
operation3()
OUTPUT:
Image Download 3 Done //Prints after 2 seconds
Image Download 2 Done //Prints after 4 seconds
Image Download 1 Done //Prints after 6 seconds
Now the question arises if I want to get below 2 scenarios -
I want operation2 to start after my operation1 finishes, and operation3 to start after operation2 finishes. So that all operations are completed in combined (6.0+4.0+2.0) 12.0 seconds.
I want all operations to start simultaneously, but completions to trigger in order they were entered in queue. So that all operations are completed in combined 6.0 seconds.
I tried serial queue and concurrent queue with sync/async blocks, but everytime answer is same. Please guide.
Suppose you have an array with imageURLs that contains all image URL that you want to download.
let imageUrls = ["imageUrl1","imageUrl2","imageUrl3"]
Here is the block method that will process operation ex: image download in this case.
func getResult(url:String, completion: #escaping (Any?) -> Void) {
.... // THIS IS YOUR PROCESS THAT YOU WANT TO EXECUTE
// After completing process you got the image
completion(image)
}
In the completion block, you just pass the value that you have got (image in this case)
Now, this is the main process to use the getResult block method. Suppose you have a method like downloadAllImages that need imageUrls.
func downloadAllImages(imageUrls: [String]) {
var imageUrls = imageUrls
if imageUrls.count > 0 {
getResult(url: imageUrls[0]) { (data) in
// Now you are in the Main thread
// here data is the output got the output
imageUrls.remove(at: 0)// remove the down element
downloadAllImages(imageUrls: imageUrls) // Again call the next one
}
}
}
Hope you understand.
The point of asyncAfter(deadline:) is to submit a block to the queue at some point in the future. But what you're saying is that you want to submit a block now and have it block the queue until it has completed. First, if you want things to occur in order, then you want a serial queue (and in fact you almost always want a serial queue).
let downloadQueue = DispatchQueue(label: "com.image.download")
Then you're saying you have a task that you want to take 6 seconds, and block the queue until it's done. That's generally not something you should do, but for testing it's of course fine, and you'd use sleep to achieve it. (You should almost never use sleep, but again, for testing it's fine.)
let operation1 = {
Thread.sleep(forTimeInterval: 6)
print("Image Download 1 Done")
}
let operation2 = {
Thread.sleep(forTimeInterval: 4)
print("Image Download 2 Done")
}
let operation3 = {
Thread.sleep(forTimeInterval: 2)
print("Image Download 3 Done")
}
And submit them:
downloadQueue.async(execute: operation1)
downloadQueue.async(execute: operation2)
downloadQueue.async(execute: operation3)
If, alternately, you want these to run in parallel, you can use a concurrent queue instead.
For non-testing situations, there are other techniques you generally should use (most commonly DispatchGroup), but for something where you're just simulating something taking time, this is fine.
You said:
Now the question arises if I want to get below 2 scenarios -
I want operation2 to start after my operation1 finishes, and operation3 to start after operation2 finishes. So that all operations are completed in combined (6.0+4.0+2.0) 12.0 seconds.
First, this is a pattern generally to be avoided with network requests because you’re going to magnify network latency effects. You would only use this pattern where absolutely needed, e.g. if request 1 was a “sign in” operation; or, you needed something returned in the first request in order to prepare the subsequent request).
Often we’d do something simple, such as initiating the subsequent request in the completion handler of the first. Or, if you wanted a more flexible set of dependencies from a series of requests, you adopt a pattern that doesn’t use dispatch queues, e.g. you might create a custom, asynchronous Operation subclass that only completes when the network request is done (see point 3 in https://stackoverflow.com/a/57247869/1271826). Or if targeting recent OS versions, you might use Combine. There are a whole bunch of alternatives here. But you can’t just start a bunch of asynchronous tasks and have them run sequentially without one of these sorts of patterns.
I want all operations to start simultaneously, but completions to trigger in order they were entered in queue. So that all operations are completed in combined 6.0 seconds.
The whole idea of concurrent patterns is that you shouldn’t care about the order that they finish. So, use a structure that is not order-dependent, and then you can store the results as they come in. And use dispatch group to know when they’re all done.
But one thing at a time. First, how do you know when a bunch of concurrent requests are done? Dispatch groups. For example:
let group = DispatchGroup()
group.enter()
queue.asyncAfter(deadline: .now() + 6) {
defer { group.leave() }
print("Image Download 1 Done")
}
group.enter()
queue.asyncAfter(deadline: .now() + 4) {
defer { group.leave() }
print("Image Download 2 Done")
}
group.enter()
queue.asyncAfter(deadline: .now() + 2) {
defer { group.leave() }
print("Image Download 3 Done")
}
group.notify(queue: .main) {
// all three are done
}
Now, how do you take these requests, store the results, and retrieve them in the original order when you’re all done? First, create some structure that is independent of the order of the tasks. For example, let’s say you were downloading a bunch of images from URLs, then create a dictionary.
var images: [URL: UIImage] = [:]
Now fire off the requests concurrently:
for url in urls {
group.enter()
downloadImage(url) { result in
defer { group.leave() }
// do something with the result, e.g. store it in our `images` dictionary
switch result {
case .failure(let error): print(error)
case .success(let image): images[url] = image
}
}
}
// this will be called on main queue when they’re all done
group.notify(queue: .main) {
// if you want to pull them in the original order, just iterate through your array
for url in urls {
if let image = images[url] {
print("image \(url) has \(image.size)")
}
}
}
By the way, the above is using the following method to retrieve the images:
enum DownloadError: Error {
case unknown(Data?, URLResponse?)
}
#discardableResult
func downloadImage(_ url: URL, completion: #escaping (Result<UIImage, Error>) -> Void) -> URLSessionTask {
let task = URLSession.shared.dataTask(with: url) { data, response, error in
guard
let responseData = data,
let image = UIImage(data: responseData),
let httpResponse = response as? HTTPURLResponse,
200 ..< 300 ~= httpResponse.statusCode,
error == nil
else {
DispatchQueue.main.async {
completion(.failure(error ?? DownloadError.unknown(data, response)))
}
return
}
DispatchQueue.main.async {
completion(.success(image))
}
}
task.resume()
return task
}
The details here are not relevant. The key observation is that you should embrace concurrent patterns for determining when tasks are done (using dispatch groups, for example) and retrieving the results (store results in an unordered structure and access them in a manner that honors the order you intended).

When to use Semaphore instead of Dispatch Group?

I would assume that I am aware of how to work with DispatchGroup, for understanding the issue, I've tried:
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
performUsingGroup()
}
func performUsingGroup() {
let dq1 = DispatchQueue.global(qos: .userInitiated)
let dq2 = DispatchQueue.global(qos: .userInitiated)
let group = DispatchGroup()
group.enter()
dq1.async {
for i in 1...3 {
print("\(#function) DispatchQueue 1: \(i)")
}
group.leave()
}
group.wait()
dq2.async {
for i in 1...3 {
print("\(#function) DispatchQueue 2: \(i)")
}
}
group.notify(queue: DispatchQueue.main) {
print("done by group")
}
}
}
and the result -as expected- is:
performUsingGroup() DispatchQueue 1: 1
performUsingGroup() DispatchQueue 1: 2
performUsingGroup() DispatchQueue 1: 3
performUsingGroup() DispatchQueue 2: 1
performUsingGroup() DispatchQueue 2: 2
performUsingGroup() DispatchQueue 2: 3
done by group
For using the Semaphore, I implemented:
func performUsingSemaphore() {
let dq1 = DispatchQueue.global(qos: .userInitiated)
let dq2 = DispatchQueue.global(qos: .userInitiated)
let semaphore = DispatchSemaphore(value: 1)
dq1.async {
semaphore.wait()
for i in 1...3 {
print("\(#function) DispatchQueue 1: \(i)")
}
semaphore.signal()
}
dq2.async {
semaphore.wait()
for i in 1...3 {
print("\(#function) DispatchQueue 2: \(i)")
}
semaphore.signal()
}
}
and called it in the viewDidLoad method. The result is:
performUsingSemaphore() DispatchQueue 1: 1
performUsingSemaphore() DispatchQueue 1: 2
performUsingSemaphore() DispatchQueue 1: 3
performUsingSemaphore() DispatchQueue 2: 1
performUsingSemaphore() DispatchQueue 2: 2
performUsingSemaphore() DispatchQueue 2: 3
Conceptually, both of DispachGroup and Semaphore serve the same purpose (unless I misunderstand something).
Honestly, I am unfamiliar with: when to use the Semaphore, especially when workin with DispachGroup -probably- handles the issue.
What is the part that I am missing?
Conceptually, both of DispatchGroup and Semaphore serve the same purpose (unless I misunderstand something).
The above is not exactly true. You can use a semaphore to do the same thing as a dispatch group but it is much more general.
Dispatch groups are used when you have a load of things you want to do that can all happen at once, but you need to wait for them all to finish before doing something else.
Semaphores can be used for the above but they are general purpose synchronisation objects and can be used for many other purposes too. The concept of a semaphore is not limited to Apple and can be found in many operating systems.
In general, a semaphore has a value which is a non negative integer and two operations:
wait If the value is not zero, decrement it, otherwise block until something signals the semaphore.
signal If there are threads waiting, unblock one of them, otherwise increment the value.
Needless to say both operations have to be thread safe. In olden days, when you only had one CPU, you'd simply disable interrupts whilst manipulating the value and the queue of waiting threads. Nowadays, it is more complicated because of multiple CPU cores and on chip caches etc.
A semaphore can be used in any case where you have a resource that can be accessed by at most N threads at the same time. You set the semaphore's initial value to N and then the first N threads that wait on it are not blocked but the next thread has to wait until one of the first N threads has signaled the semaphore. The simplest case is N = 1. In that case, the semaphore behaves like a mutex lock.
A semaphore can be used to emulate a dispatch group. You start the sempahore at 0, start all the tasks - tracking how many you have started and wait on the semaphore that number of times. Each task must signal the semaphore when it completes.
However, there are some gotchas. For example, you need a separate count to know how many times to wait. If you want to be able to add more tasks to the group after you have started waiting, the count can only be updated in a mutex protected block and that may lead to problems with deadlocking. Also, I think the Dispatch implementation of semaphores might be vulnerable to priority inversion. Priority inversion occurs when a high priority thread waits for a resource that a low priority has grabbed. The high priority thread is blocked until the low priority thread releases the resource. If there is a medium priority thread running, this may never happen.
You can pretty much do anything with a semaphore that other higher level synchronisation abstractions can do, but doing it right is often a tricky business to get right. The higher level abstractions are (hopefully) carefully written and you should use them in preference to a "roll your own" implementation with semaphores, if possible.
Semaphores and groups have, in a sense, opposite semantics. Both maintain a count. With a semaphore, a wait is allowed to proceed when the count is non-zero. With a group, a wait is allowed to proceed when the count is zero.
A semaphore is useful when you want to set a maximum on the number of threads operating on some shared resource at a time. One common use is when the maximum is 1 because the shared resource requires exclusive access.
A group is useful when you need to know when a bunch of tasks have all been completed.
Use a semaphore to limit the amount of concurrent work at a given time. Use a group to wait for any number of concurrent work to finish execution.
In case you wanted to submit three jobs per queue it should be
import Foundation
func performUsingGroup() {
let dq1 = DispatchQueue(label: "q1", attributes: .concurrent)
let dq2 = DispatchQueue(label: "q2", attributes: .concurrent)
let group = DispatchGroup()
for i in 1...3 {
group.enter()
dq1.async {
print("\(#function) DispatchQueue 1: \(i)")
group.leave()
}
}
for i in 1...3 {
group.enter()
dq2.async {
print("\(#function) DispatchQueue 2: \(i)")
group.leave()
}
}
group.notify(queue: DispatchQueue.main) {
print("done by group")
}
}
performUsingGroup()
RunLoop.current.run(mode: RunLoop.Mode.default, before: Date(timeIntervalSinceNow: 1))
and
import Foundation
func performUsingSemaphore() {
let dq1 = DispatchQueue(label: "q1", attributes: .concurrent)
let dq2 = DispatchQueue(label: "q2", attributes: .concurrent)
let semaphore = DispatchSemaphore(value: 1)
for i in 1...3 {
dq1.async {
_ = semaphore.wait(timeout: DispatchTime.distantFuture)
print("\(#function) DispatchQueue 1: \(i)")
semaphore.signal()
}
}
for i in 1...3 {
dq2.async {
_ = semaphore.wait(timeout: DispatchTime.distantFuture)
print("\(#function) DispatchQueue 2: \(i)")
semaphore.signal()
}
}
}
performUsingSemaphore()
RunLoop.current.run(mode: RunLoop.Mode.default, before: Date(timeIntervalSinceNow: 1))
The replies above by Jano and Ken are correct regarding 1) the use of semaphore to limit the amount of work happening at once 2) the use of a dispatch group so that the group will be notified when all the tasks in the group are done. For example, you may want to download a lot of images in parallel but since you know that they are heavy images, you want to limit to two downloads only at a single time so you use a semaphore. You also want to be notified when all the downloads (say there are 50 of them) are done, so you use DispatchGroup. Thus, it is not a matter of choosing between the two. You may use one or both in the same implementation depending on your goals. This type of example was provided in the Concurrency tutorial on Ray Wenderlich's site:
let group = DispatchGroup()
let queue = DispatchQueue.global(qos: .utility)
let semaphore = DispatchSemaphore(value: 2)
let base = "https://yourbaseurl.com/image-id-"
let ids = [0001, 0002, 0003, 0004, 0005, 0006, 0007, 0008, 0009, 0010, 0011, 0012]
var images: [UIImage] = []
for id in ids {
guard let url = URL(string: "\(base)\(id)-jpeg.jpg") else { continue }
semaphore.wait()
group.enter()
let task = URLSession.shared.dataTask(with: url) { data, _, error in
defer {
group.leave()
semaphore.signal()
}
if error == nil,
let data = data,
let image = UIImage(data: data) {
images.append(image)
}
}
task.resume()
}
One typical semaphore use case is a function that can be called simultaneously from different threads and uses a resource that should not be called from multiple threads at the same time:
func myFunction() {
semaphore.wait()
// access the shared resource
semaphore.signal()
}
In this case you will be able to call myFunction from different threads but they won't be able to reach the locked resource simultaneously. One of them will have to wait until the second one finishes its work.
A semaphore keeps a count, therefore you can actually allow for a given number of threads to enter your function at the same time.
Typical shared resource is the output to a file.
A semaphore is not the only way to solve such problems. You can also add the code to a serial queue, for example.
Semaphores are low level primitives and most likely they are used a lot under the hood in GCD.
Another typical example is the producer-consumer problem, where the signal and wait calls are actually part of two different functions. One which produces data and one which consumes them.
Generally semaphore can be considered mainly that we can solve the critical section problem. Locking certain resource to achieve synchronisation. Also what happens if sleep() is invoked, can we achieve the same thing by using a semaphore ?
Dispatch groups we will use when we have multiple group of operations to be carried out and we need a tracking or set dependencies each other or notification when a group os tasks finishes its execution.

Swift 3 Cannot convert value of type '()' to expected argument type '__OS_dispatch_queue_attr?' [duplicate]

In Swift 2, I was able to create queue with the following code:
let concurrentQueue = dispatch_queue_create("com.swift3.imageQueue", DISPATCH_QUEUE_CONCURRENT)
But this doesn't compile in Swift 3.
What is the preferred way to write this in Swift 3?
Creating a concurrent queue
let concurrentQueue = DispatchQueue(label: "queuename", attributes: .concurrent)
concurrentQueue.sync {
}
Create a serial queue
let serialQueue = DispatchQueue(label: "queuename")
serialQueue.sync {
}
Get main queue asynchronously
DispatchQueue.main.async {
}
Get main queue synchronously
DispatchQueue.main.sync {
}
To get one of the background thread
DispatchQueue.global(qos: .background).async {
}
Xcode 8.2 beta 2:
To get one of the background thread
DispatchQueue.global(qos: .default).async {
}
DispatchQueue.global().async {
// qos' default value is ´DispatchQoS.QoSClass.default`
}
If you want to learn about using these queues .See this answer
Compiles under >=Swift 3. This example contains most of the syntax that we need.
QoS - new quality of service syntax
weak self - to disrupt retain cycles
if self is not available, do nothing
async global utility queue - for network query, does not wait for the result, it is a concurrent queue, the block (usually) does not wait when started. Exception for a concurrent queue could be, when its task limit has been previously reached, then the queue temporarily turns into a serial queue and waits until some previous task in that queue completes.
async main queue - for touching the UI, the block does not wait for the result, but waits for its slot at the start. The main queue is a serial queue.
Of course, you need to add some error checking to this...
DispatchQueue.global(qos: .utility).async { [weak self] () -> Void in
guard let strongSelf = self else { return }
strongSelf.flickrPhoto.loadLargeImage { loadedFlickrPhoto, error in
if error != nil {
print("error:\(error)")
} else {
DispatchQueue.main.async { () -> Void in
activityIndicator.removeFromSuperview()
strongSelf.imageView.image = strongSelf.flickrPhoto.largeImage
}
}
}
}
Compiled in XCode 8, Swift 3
https://github.com/rpthomas/Jedisware
#IBAction func tap(_ sender: AnyObject) {
let thisEmail = "emailaddress.com"
let thisPassword = "myPassword"
DispatchQueue.global(qos: .background).async {
// Validate user input
let result = self.validate(thisEmail, password: thisPassword)
// Go back to the main thread to update the UI
DispatchQueue.main.async {
if !result
{
self.displayFailureAlert()
}
}
}
}
Since the OP question has already been answered above I just want to add some speed considerations:
It makes a lot of difference what priority class you assign to your async function in DispatchQueue.global.
I don't recommend running tasks with the .background thread priority especially on the iPhone X where the task seems to be allocated on the low power cores.
Here is some real data from a computationally intensive function that reads from an XML file (with buffering) and performs data interpolation:
Device name / .background / .utility / .default / .userInitiated / .userInteractive
iPhone X: 18.7s / 6.3s / 1.8s / 1.8s / 1.8s
iPhone 7: 4.6s / 3.1s / 3.0s / 2.8s / 2.6s
iPhone 5s: 7.3s / 6.1s / 4.0s / 4.0s / 3.8s
Note that the data set is not the same for all devices. It's the biggest on the iPhone X and the smallest on the iPhone 5s.
Update for swift 5
Serial Queue
let serialQueue = DispatchQueue.init(label: "serialQueue")
serialQueue.async {
// code to execute
}
Concurrent Queue
let concurrentQueue = DispatchQueue.init(label: "concurrentQueue", qos: .background, attributes: .concurrent, autoreleaseFrequency: .inherit, target: nil)
concurrentQueue.async {
// code to execute
}
From Apple documentation:
Parameters
label
A string label to attach to the queue to uniquely identify it in debugging tools such as Instruments, sample, stackshots, and crash reports. Because applications, libraries, and frameworks can all create their own dispatch queues, a reverse-DNS naming style (com.example.myqueue) is recommended. This parameter is optional and can be NULL.
qos
The quality-of-service level to associate with the queue. This value determines the priority at which the system schedules tasks for execution. For a list of possible values, see DispatchQoS.QoSClass.
attributes
The attributes to associate with the queue. Include the concurrent attribute to create a dispatch queue that executes tasks concurrently. If you omit that attribute, the dispatch queue executes tasks serially.
autoreleaseFrequency
The frequency with which to autorelease objects created by the blocks that the queue schedules. For a list of possible values, see DispatchQueue.AutoreleaseFrequency.
target
The target queue on which to execute blocks. Specify DISPATCH_TARGET_QUEUE_DEFAULT if you want the system to provide a queue that is appropriate for the current object.
I did this and this is especially important if you want to refresh your UI to show new data without user noticing like in UITableView or UIPickerView.
DispatchQueue.main.async
{
/*Write your thread code here*/
}
DispatchQueue.main.async {
self.collectionView?.reloadData() // Depends if you were populating a collection view or table view
}
OperationQueue.main.addOperation {
self.lblGenre.text = self.movGenre
}
//use Operation Queue if you need to populate the objects(labels, imageview, textview) on your viewcontroller
let concurrentQueue = dispatch_queue_create("com.swift3.imageQueue", DISPATCH_QUEUE_CONCURRENT) //Swift 2 version
let concurrentQueue = DispatchQueue(label:"com.swift3.imageQueue", attributes: .concurrent) //Swift 3 version
I re-worked your code in Xcode 8, Swift 3 and the changes are marked in contrast to your Swift 2 version.
Swift 3
you want call some closure in swift code then you want to change in storyboard ya any type off change belong to view your application will crash
but you want to use dispatch method your application will not crash
async method
DispatchQueue.main.async
{
//Write code here
}
sync method
DispatchQueue.main.sync
{
//Write code here
}
DispatchQueue.main.async(execute: {
// write code
})
Serial Queue :
let serial = DispatchQueue(label: "Queuename")
serial.sync {
//Code Here
}
Concurrent queue :
let concurrent = DispatchQueue(label: "Queuename", attributes: .concurrent)
concurrent.sync {
//Code Here
}
For Swift 3
DispatchQueue.main.async {
// Write your code here
}
let newQueue = DispatchQueue(label: "newname")
newQueue.sync {
// your code
}
it is now simply:
let serialQueue = DispatchQueue(label: "my serial queue")
the default is serial, to get concurrent, you use the optional attributes argument .concurrent
DispatchQueue.main.async(execute: {
// code
})
You can create dispatch queue using this code in swift 3.0
DispatchQueue.main.async
{
/*Write your code here*/
}
/* or */
let delayTime = DispatchTime.now() + Double(Int64(0.5 * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC)
DispatchQueue.main.asyncAfter(deadline: delayTime)
{
/*Write your code here*/
}

How to create dispatch queue in Swift 3

In Swift 2, I was able to create queue with the following code:
let concurrentQueue = dispatch_queue_create("com.swift3.imageQueue", DISPATCH_QUEUE_CONCURRENT)
But this doesn't compile in Swift 3.
What is the preferred way to write this in Swift 3?
Creating a concurrent queue
let concurrentQueue = DispatchQueue(label: "queuename", attributes: .concurrent)
concurrentQueue.sync {
}
Create a serial queue
let serialQueue = DispatchQueue(label: "queuename")
serialQueue.sync {
}
Get main queue asynchronously
DispatchQueue.main.async {
}
Get main queue synchronously
DispatchQueue.main.sync {
}
To get one of the background thread
DispatchQueue.global(qos: .background).async {
}
Xcode 8.2 beta 2:
To get one of the background thread
DispatchQueue.global(qos: .default).async {
}
DispatchQueue.global().async {
// qos' default value is ´DispatchQoS.QoSClass.default`
}
If you want to learn about using these queues .See this answer
Compiles under >=Swift 3. This example contains most of the syntax that we need.
QoS - new quality of service syntax
weak self - to disrupt retain cycles
if self is not available, do nothing
async global utility queue - for network query, does not wait for the result, it is a concurrent queue, the block (usually) does not wait when started. Exception for a concurrent queue could be, when its task limit has been previously reached, then the queue temporarily turns into a serial queue and waits until some previous task in that queue completes.
async main queue - for touching the UI, the block does not wait for the result, but waits for its slot at the start. The main queue is a serial queue.
Of course, you need to add some error checking to this...
DispatchQueue.global(qos: .utility).async { [weak self] () -> Void in
guard let strongSelf = self else { return }
strongSelf.flickrPhoto.loadLargeImage { loadedFlickrPhoto, error in
if error != nil {
print("error:\(error)")
} else {
DispatchQueue.main.async { () -> Void in
activityIndicator.removeFromSuperview()
strongSelf.imageView.image = strongSelf.flickrPhoto.largeImage
}
}
}
}
Compiled in XCode 8, Swift 3
https://github.com/rpthomas/Jedisware
#IBAction func tap(_ sender: AnyObject) {
let thisEmail = "emailaddress.com"
let thisPassword = "myPassword"
DispatchQueue.global(qos: .background).async {
// Validate user input
let result = self.validate(thisEmail, password: thisPassword)
// Go back to the main thread to update the UI
DispatchQueue.main.async {
if !result
{
self.displayFailureAlert()
}
}
}
}
Since the OP question has already been answered above I just want to add some speed considerations:
It makes a lot of difference what priority class you assign to your async function in DispatchQueue.global.
I don't recommend running tasks with the .background thread priority especially on the iPhone X where the task seems to be allocated on the low power cores.
Here is some real data from a computationally intensive function that reads from an XML file (with buffering) and performs data interpolation:
Device name / .background / .utility / .default / .userInitiated / .userInteractive
iPhone X: 18.7s / 6.3s / 1.8s / 1.8s / 1.8s
iPhone 7: 4.6s / 3.1s / 3.0s / 2.8s / 2.6s
iPhone 5s: 7.3s / 6.1s / 4.0s / 4.0s / 3.8s
Note that the data set is not the same for all devices. It's the biggest on the iPhone X and the smallest on the iPhone 5s.
Update for swift 5
Serial Queue
let serialQueue = DispatchQueue.init(label: "serialQueue")
serialQueue.async {
// code to execute
}
Concurrent Queue
let concurrentQueue = DispatchQueue.init(label: "concurrentQueue", qos: .background, attributes: .concurrent, autoreleaseFrequency: .inherit, target: nil)
concurrentQueue.async {
// code to execute
}
From Apple documentation:
Parameters
label
A string label to attach to the queue to uniquely identify it in debugging tools such as Instruments, sample, stackshots, and crash reports. Because applications, libraries, and frameworks can all create their own dispatch queues, a reverse-DNS naming style (com.example.myqueue) is recommended. This parameter is optional and can be NULL.
qos
The quality-of-service level to associate with the queue. This value determines the priority at which the system schedules tasks for execution. For a list of possible values, see DispatchQoS.QoSClass.
attributes
The attributes to associate with the queue. Include the concurrent attribute to create a dispatch queue that executes tasks concurrently. If you omit that attribute, the dispatch queue executes tasks serially.
autoreleaseFrequency
The frequency with which to autorelease objects created by the blocks that the queue schedules. For a list of possible values, see DispatchQueue.AutoreleaseFrequency.
target
The target queue on which to execute blocks. Specify DISPATCH_TARGET_QUEUE_DEFAULT if you want the system to provide a queue that is appropriate for the current object.
I did this and this is especially important if you want to refresh your UI to show new data without user noticing like in UITableView or UIPickerView.
DispatchQueue.main.async
{
/*Write your thread code here*/
}
DispatchQueue.main.async {
self.collectionView?.reloadData() // Depends if you were populating a collection view or table view
}
OperationQueue.main.addOperation {
self.lblGenre.text = self.movGenre
}
//use Operation Queue if you need to populate the objects(labels, imageview, textview) on your viewcontroller
let concurrentQueue = dispatch_queue_create("com.swift3.imageQueue", DISPATCH_QUEUE_CONCURRENT) //Swift 2 version
let concurrentQueue = DispatchQueue(label:"com.swift3.imageQueue", attributes: .concurrent) //Swift 3 version
I re-worked your code in Xcode 8, Swift 3 and the changes are marked in contrast to your Swift 2 version.
Swift 3
you want call some closure in swift code then you want to change in storyboard ya any type off change belong to view your application will crash
but you want to use dispatch method your application will not crash
async method
DispatchQueue.main.async
{
//Write code here
}
sync method
DispatchQueue.main.sync
{
//Write code here
}
DispatchQueue.main.async(execute: {
// write code
})
Serial Queue :
let serial = DispatchQueue(label: "Queuename")
serial.sync {
//Code Here
}
Concurrent queue :
let concurrent = DispatchQueue(label: "Queuename", attributes: .concurrent)
concurrent.sync {
//Code Here
}
For Swift 3
DispatchQueue.main.async {
// Write your code here
}
let newQueue = DispatchQueue(label: "newname")
newQueue.sync {
// your code
}
it is now simply:
let serialQueue = DispatchQueue(label: "my serial queue")
the default is serial, to get concurrent, you use the optional attributes argument .concurrent
DispatchQueue.main.async(execute: {
// code
})
You can create dispatch queue using this code in swift 3.0
DispatchQueue.main.async
{
/*Write your code here*/
}
/* or */
let delayTime = DispatchTime.now() + Double(Int64(0.5 * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC)
DispatchQueue.main.asyncAfter(deadline: delayTime)
{
/*Write your code here*/
}

Resources