I want to setup a serialized task queue using NSOperationQueue but I'm a little confused by the terminology discussed in the documentation.
In the context of an NSOperation
object, the terms concurrent and
non-concurrent do not necessarily
refer to the side-by-side execution of
threads. Instead, a non-concurrent
operation is one that executes using
the environment that is provided for
it while a concurrent operation is
responsible for setting up its own
execution environment.
What does it mean to setup "own execution environment'?
My NSOperation derived tasks need to execute serially in the order they were added to the queue.
So I thought that this implies a 'non-concurrent' operation so I'd implement 'main' for the work that needs to be completed and also return NO for 'isConcurrent'. In addition, NSOperationQueue's 'setMaxConcurrentOperationCount' would be set to 1.
The reason I am not setting up NSOperation dependency between these tasks is because the order they're inserted into the queue is the order they should be completed.
Are these assumptions correct?
NSOperationQueue always executes operations concurrently, while taking dependencies into account.
A "non-concurrent" operation requires a separate thread in order to execute concurrently. NSOperationQueue is responsible for providing this thread. In other words, a non-concurrent operation depends on NSOperationQueue to make it a concurrent operation.
A "concurrent" operation is concurrent on its own; it doesn't need NSOperationQueue to create a thread for it. An example would be an operation that uses asynchronous file IO.
If you want two or more operations to execute serially you need to use dependencies.
If you want an operation to block the main thread then don't use NSOperationQueue; just run each operation one after the other on the main thread.
To manually set maximum of concurrent operations, use method on operationQueue setMaxConcurrentOperationCount:
Do you really need to subclass NSOperation? Why not just use NSInvocationOperation and its addDependency: method?
See my answer in this SO question.
Related
After reading about Concurrent and Serial queues, sync and async, I think I have an idea about how to create queues and the order they are executed in. My problem is that in any of the tutorials I have seen, none of them actually tell you many use cases. For example:
I have a network manager that uses URLSessions and serializes json to send a request to my api. Does it make sense to wrap it in a .utility Queue or in a .userInitiated or do I just don't wrap it in a queue.
let task = LoginTask(username: username, password: password)
let networkQueue = DispatchQueue(label: "com.messenger.network",
qos: DispatchQoS.userInitiated)
networkQueue.async {
task.dataTask(in: dispatcher) { (user, httpCode, error) in
self.presenter?.loginUserResponse(user: user, httpCode: httpCode, error: error)
}
}
My question is: Is there any guidlines I can follow to know when there is a need to use queues or not because I cant find this information anywhere. I realise apple provides example usage howver it is very vague
Dispatch queues are used in a multitude of use cases, so it's hard to enumerate them, but two very common use cases are as follows:
You have some expensive and/or time-consuming process that you want to run on some thread other than the current thread. Often this is used when you're on the main thread and you want to run something on a background thread.
A good example of this would be image manipulation, which is a notoriously computationally (and memory) intensive process. So, you'd create a queue for image manipulation and then you'd dispatch each image manipulation task to that queue. You might also dispatch the UI update when it's done back to the main queue (because all UI updates must happen on the main thread). A common pattern would be:
imageQueue.async {
// manipulate the image here
// when done, update the UI:
DispatchQueue.main.async {
// update the UI and/or model objects on the main thread
}
}
You have some shared resource (it could be a simple variable, it could be some interaction with some other shared resource like a file or database) that you want to synchronize regardless of from which thread to invoke it. This is often part of a broader strategy of making something that is not inherently thread-safe behave in a thread safe manner.
The virtue of dispatch queues is that it greatly simplifies writing multi-threaded code, an otherwise very complicated technology.
The thing is that your example, initiating a network request, already runs the request on a background thread and URLSession manages all of this for you, so there's little value in using queues for that.
In the interest of full disclosure, there is a surprising of variety of different tools using GCD directly (e.g. dispatch groups or dispatch sources) or indirectly (e.g. operation queues) above and beyond the basic dispatch queues discussed above:
Dispatch groups: Sometimes you will initiate a series of asynchronous tasks and you want to be notified when they're all done. You can use a dispatch group (see https://stackoverflow.com/a/28101212/1271826 for a random example). This eliminates you from needing to keep track of when all of these tasks are done yourself.
Dispatch "apply" (now called concurrentPerform): Sometimes when you're running some massively parallel task, you want to use as many threads as you reasonably can. So concurrentPerform lets you effectively perform a for loop in parallel, and Apple has optimized it for the number of cores and CPUs your particular device, while not flooding it with too many concurrent tasks at any one time, exhausting the limited number of worker threads. See the https://stackoverflow.com/a/39949292/1271826 for an example of running a for loop in parallel.
Dispatch sources:
For example, if you have some background task that is doing a lot of work and you want to update the UI with the progress, sometimes those UI updates can come more quickly than the UI can handle them. So you can use a dispatch source (a DispatchSourceUserDataAdd) to decouple the background process from the UI updates. See aforementioned https://stackoverflow.com/a/39949292/1271826 for an example.
Traditionally, a Timer runs on the main run loop. But sometimes you want to run it on a background thread, but doing that with a Timer is complicated. But you can use a DispatchSourceTimer (a GCD timer) to run a timer on a queue other than the main queue. See https://stackoverflow.com/a/38164203/1271826 for example of how to create and use a dispatch timer. Dispatch timers also can be used to avoid some of the strong reference cycles that are easily introduced with target-based Timer objects.
Barriers: Sometimes when using a concurrent queue, you want most things to run concurrently, but for other things to run serially with respect to everything else on the queue. A barrier is a way to say "add this task to the queue, but make sure it doesn't run concurrently with respect to anything else on that queue."
An example of a barrier is the reader-writer pattern, where reading from some memory resource can happen concurrently with respect to all other reads, but any writes must not happen concurrently with respect to anything else on the queue. See https://stackoverflow.com/a/28784770/1271826 or https://stackoverflow.com/a/45628393/1271826.
Dispatch semaphores: Sometimes you need to let two tasks running on separate threads communicate to each other. You can use semaphores for one thread to "wait" for the "signal" from another.
One common application of semaphores is to make an inherently asynchronous task behave in a more synchronous manner.
networkQueue.async {
let semaphore = DispatchSemaphore(0)
let task = session.dataTask(with: url) { data, _, error in
// process the response
// when done, signal that we're done
semaphore.signal()
}
task.resume()
semaphore.wait(timeout: .distantFuture)
}
The virtue of this approach is that the dispatched task won't finish until the asynchronous network request is done. So if you needed to issue a series of network requests, but not have them run concurrently, semaphores can accomplish that.
Semaphores should be used sparingly, though, because they're inherently inefficient (generally blocking one thread waiting for another). Also, make sure you never wait for a semaphore from the main thread (because you're defeating the purpose of having the asynchronous task). That's why in the above example, I'm waiting on the networkQueue, not the main queue. All of this having been said, there's often better techniques than semaphores, but it is sometimes useful.
Operation queues: Operation queues are built on top of GCD dispatch queues, but offer some interesting advantages including:
The ability to wrap an inherently asynchronous task in a custom Operation subclass. (This avoids the disadvantages of the semaphore technique I discussed earlier.) Dispatch queues are generally used when running inherently synchronous tasks on a background thread, but sometimes you want to manage a bunch of tasks that are, themselves, asynchronous. A common example is the wrapping of asynchronous network requests in Operation subclass.
The ability to easily control the degree of concurrency. Dispatch queues can be either serial or concurrent, but it's cumbersome to design the control mechanism to, for example, to say "run the queued tasks concurrent with respect to each other, but no more than four at any given time." Operation queues make this much easier with the use of maxConcurrentOperationCount. (See https://stackoverflow.com/a/27022598/1271826 for an example.)
The ability to establish dependencies between various tasks (e.g. you might have a queue for downloading images and another queue for manipulating the images). With operation queues you can have one operation for the downloading of an image and another for the processing of the image, and you can make the latter dependent upon the completion of the former.
There are lots of other GCD related applications and technologies, but these are a few that I use with some frequency.
Literally, this concurrency type requires an specific thread, but using a serial queue would be more easy, but is it safe to use the context with a NSConfinementConcurrencyType concurrency type on a serial dispatch queue?
As long as you're sure you only use that queue with the context, yes, that's completely fine.
Core Data doesn't care about the thread so much as it cares about concurrent access. If you serialize access, you're safe, however you choose to do it. You could use NSRecursiveLock or semaphores or whatever works for you.
Note that the newer concurrency models are queue based. NSPrivateQueueConcurrencyType does not guarantee that operations are always performed on the same thread, even when you use performBlock:. They happen on a private queue and might run on different threads at different times. If you can manage your queue and your access well enough to do this yourself, it's reasonable to do so.
No, having a serial queue does not guarantee the operations will execute on the same thread:
The Concurrency Programming Guide specifies
Serial queues (also known as private dispatch queues) execute one task
at a time in the order in which they are added to the queue. The
currently executing task runs on a distinct thread (which can vary
from task to task) that is managed by the dispatch queue. Serial
queues are often used to synchronize access to a specific resource.
Why don't you just use the NSPrivateQueueConcurrencyType? It will make your code cleaner and thread safe. You just need to call -performBlock: or -performBlockAndWait: when accessing the context from somewhere other than the block that initialized the context.
I am using NSOperationQueue to run the task. I am using background processing in my application. But while adding tasks in NSOperationQueue, I found that tasks will be added in a queue format.
Does NSOperationQueue performs parallel task or sequential task processing?
If not parallel, then how can I achieve parallel task operations in my app?
I would recommend you read this document about concurrency programming.
You can perform parallel tasks by using "performSelectorInBackground" method. In this you are just showing the foreground tasks, meanwhile background tasks is being in progress. I have already answered on the following link, please follow the link given below with accepted answer. Perhaps it will help you.
http://[stackoverflow.com/questions/8725636/cant-get-the-activity-indicator-to-show-on-iphone-app/8725875#8725875][1]
Thanks!
Regards!
Khalid Usman
Use the setMaxConcurrentOperationCount: to set the number of concurrent operations.
I would suggest that you read this. The relevant information for you is:
Operation queues work with the system to restrict the number of concurrent operations to a value that is appropriate for the available cores and system load.
Although the NSOperationQueue class is designed for the concurrent execution of operations, it is possible to force a single queue to run only one operation at a time. The setMaxConcurrentOperationCount: method lets you configure the maximum number of concurrent operations for an operation queue object. Passing a value of 1 to this method causes the queue to execute only one operation at a time. Although only one operation at a time may execute, the order of execution is still based on other factors, such as the readiness of each operation and its assigned priority.
I'm writing an app which requires running a method after another method completes. (Common scenario, right?)
I'm trying to implement chained methods. The best I've come up with is to call performSelector:withObject:afterDelay:. I'm simply not sure if that is the best way to do this. I've looked into how the Cocos2d game engine implements its CCSequence class, but I'm not sure I understand it.
I suspect blocks would do well here, except I'm not sure how to use them as callback objects or whatever.
How would I implement a mechanism for running methods, one after the other? (I'm open to using timers or blocks, but I don't know how I'd use blocks in this case.)
Edit:
To clarify, I'm trying to implement a system like cocos2d's CCSequence class, which takes a few methods and "dispatches" them in sequence. Things like animations, which take much more than a single clock cycle to run.
I'm not looking to block the main thread, nor do I want to hard code methods to each other. Cocos2d has a sequencing system where I can pass in methods to a queue and run them sequentially.
Edit 2:
Also, I'd like to be able to cancel my scheduled queues, and so I'm not sure GCD is a good match for this. Can GCD serial queues be canceled?
You can use the technique of Thread Migration
Then here comes the interesting task called GCD-Grand Central Dispatch
Grand Central Dispatch (GCD) is a technology developed by Apple Inc.
to optimize application support for systems with multi-core processors
and other symmetric multiprocessing systems.It is an implementation of
task parallelism based on the thread pool pattern.
GCD works by allowing specific tasks in a program that can be run in
parallel to be queued up for execution and, depending on availability
of processing resources, scheduling them to execute on any of the
available processor cores
Dispatch Queues are objects that maintain a queue of tasks, either anonymous code blocks or functions, and execute these tasks in their
turn. The library automatically creates several queues with different
priority levels that execute several tasks concurrently, selecting the
optimal number of tasks to run based on the operating environment. A
client to the library may also create any number of serial queues,
which execute tasks in the order they are submitted, one at a time.
Because a serial queue can only run one task at a time, each task
submitted to the queue is critical with regard to the other tasks on
the queue, and thus a serial queue can be used instead of a lock on a
contended resource.
Dispatch queues execute their tasks concurrently with respect to other
dispatch queues. The serialization of tasks is limited to the tasks in
a single dispatch queue.
In your case you can use Serial Dispatch Queues
Serial queues are useful when you want your tasks to execute in a
specific order. A serial queue executes only one task at a time and
always pulls tasks from the head of the queue. You might use a serial
queue instead of a lock to protect a shared resource or mutable data
structure. Unlike a lock, a serial queue ensures that tasks are
executed in a predictable order. And as long as you submit your tasks
to a serial queue asynchronously, the queue can never deadlock.
Unlike concurrent queues, which are created for you, you must
explicitly create and manage any serial queues you want to use. You
can create any number of serial queues for your application but should
avoid creating large numbers of serial queues solely as a means to
execute as many tasks simultaneously as you can. If you want to
execute large numbers of tasks concurrently, submit them to one of the
global concurrent queues. When creating serial queues, try to identify
a purpose for each queue, such as protecting a resource or
synchronizing some key behavior of your application.
dispatch_queue_t queue;
queue = dispatch_queue_create("com.example.MyQueue", NULL);
this code shows the steps required to create a custom serial queue.
The dispatch_queue_create function takes two parameters: the queue
name and a set of queue attributes. The debugger and performance tools
display the queue name to help you track how your tasks are being
executed. The queue attributes are reserved for future use and should
be NULL.
Grand Central Dispatch provides functions to let you access several
common dispatch queues from your application:
Use the dispatch_get_current_queue function for debugging purposes
or to test the identity of the current queue. Calling this function
from inside a block object returns the queue to which the block was
submitted (and on which it is now presumably running). Calling this
function from outside of a block returns the default concurrent queue
for your application.
Use the dispatch_get_main_queue function to get the serial
dispatch queue associated with your application’s main thread. This
queue is created automatically for Cocoa applications and for
applications that either call the dispatch_main function or configure
a run loop (using either the CFRunLoopRef type or an NSRunLoop object)
on the main thread.
Use the dispatch_get_global_queue function to get any of the
shared concurrent queues.
Note: You do not need to retain or release any of the global dispatch
queues, including the concurrent dispatch queues or the main dispatch
queue. Any attempts to retain or release the queues are ignored.
Source: Concurrency Programming Guide
What about using a serial GCD queue?
private dispatch queues
Serial queues (also known as private dispatch queues) execute one task at a time in the order in which they are added to the queue. The currently executing task runs on a distinct thread (which can vary from task to task) that is managed by the dispatch queue. Serial queues are often used to synchronize access to a specific resource.
You can create as many serial queues as you need, and each queue operates concurrently with respect to all other queues. In other words, if you create four serial queues, each queue executes only one task at a time but up to four tasks could still execute concurrently, one from each queue. For information on how to create serial queues, see “Creating Serial Dispatch Queues.”
(source)
This would be useful if you want that all of your messages be handled in a background thread.
There are two performSelector method that can wait for completion, no need to guess a timing.
[self performSelector:<#(SEL)#> onThread:<#(NSThread *)#> withObject:<#(id)#> waitUntilDone:<#(BOOL)#>];
[self performSelectorOnMainThread:<#(SEL)#> withObject:<#(id)#> waitUntilDone:<#(BOOL)#>];
It sounds like you want to check out NSOperationQueue, NSOperation, and either NSBlockOperation or NSInvocationOperation. Unlike a GCD queue, an NSOperationQueue supports cancelling jobs.
You can create your own queue and set its maximum concurrent operation count to 1 to force it to execute operations serially. Or you can set dependencies between operations to force those operations to run serially.
Start with the chapter on Operation Queues in the Concurrency Programming Guide.
I finally found what I'm looking for. Completion blocks. Simply put, I'd write a method like this:
- (void) performSomeActionWithCompletion:(void (^)()) completion{
[self someAction];
if(completion()){
completion();
}
}
Now I can call my method like so:
[self performSomeActionWithCompletion:^{
NSLog(#"All done! (Well, not the async stuff, but at any rate...)");
}];
Im using NSOperation to do a task: download some files with NSURLConnection and then merge files that spend much cpu and memory
I need to excute the task in new/background thread
So I add some these tasks to NSOperationQueue and set maxConcurrentOperationCount = 2
But the result is when merging files it will block the main thread(UI not respond for a while)
,it seems not excuting in new/background thread
how to make it go as I expected ?
What type of operations are you putting in the NSOperationQueue? Apple's documentation for the NSOperationQueue includes this note:
Note: In iOS, operation queues do not
use Grand Central Dispatch to execute
operations. They create separate
threads for non-concurrent operations
and launch concurrent operations from
the current thread. For a discussion
of the difference between concurrent
and non-concurrent operations and how
they are executed, see NSOperation Class Reference.
Since you using NSOperationqueue,therefore you are having only two files at one time and you can merge only them because all the other threads or files are not present there.
So for merging them together you will have to keep them together at one time.