I've created a system where i can request an NSManagedObjectContext from a singleton object, dependant on the queue it's running on. Every serial GCD dispatch queue is associated with a certain task, and thus gets its own context, though all with the same persistent store coordinator.
I was under the assumption that this would solve my problems associated with threads, which it so far seems to have done, but now i have a different problem: If 2 serial queues, with different MOCs, both try to make the context execute, they both lock and the app freezes. So what did i miss?
"...[I]f you create one context per thread, but all pointing to the same persistent store coordinator, Core Data takes care of accessing the coordinator in a thread-safe way (the lock and unlock methods of NSManagedObjectContext handle recursion)." (source)
What i read there, is that Core Data should handle locking and unlocking correctly with my setup. Or do i understand 'in a thread-safe way' wrong in this case?
Edit: I basically have a dictionary that maps a queue to a context. At first i wanted to work with threads instead of queues, until i read this part:
"Note: You can use threads, serial operation queues, or dispatch queues for concurrency. For the sake of conciseness, this article uses “thread” throughout to refer to any of these." (source)
If by "serial queue" you mean GCD dispatch queue or NSOperationQueue, you are making incorrect assumptions that each queue has a dedicated thread or that the tasks for each queue always run on the same thread.
You need to figure out a way of mapping a thread to a managed object context, perhaps by way of an NSDictionary and when you run a task on your queue, get the MOC associated with the current thread.
JeremyP is right: queues do not == threads. A queue may create a new thread for each operation - Core Data (in the default mode) requires thread confinement (that is, the thread that created the NSManagedObjectContext must be the thread used for all access to any objects from that context).
You may want to check how the confinement options are used - if you're targeting iOS5 alone, you might be able to change it without too much difficulty and still use the queues.
Related
I'm working with sqlite so I need to guarantee the thread my calls execute on, but I don't want to use the main thread. I could subclass Thread, however that introduces a host of issues trying to create async methods and executing blocks of code in the thread's main loop.
If instead I used an actor instead of a Thread subclass, will all the work within that actor be guaranteed to be on the same thread? I don't see that defined anywhere in the documentation so I'm guessing no.
You asked:
Does an actor guarantee the same execution thread?
No, it does not. (Neither does GCD serial queue, for that matter.)
But SQLite does not care from which thread you call it. It only cares that you don't call it from different threads simultaneously.
So, you do not have to ”to guarantee the thread my calls execute on“, but merely ensure that you don't have two threads interacting with the same connection at the same time. This is precisely the assurance that actor-isolated functions provide.
So, do not worry about what thread the actor happens to use. Only make sure you don't have simultaneous access from multiple threads at the same time.
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.
The following senario was done using threads
A large queue #work_queue populated/enqueued by the main thread. Used Thread::Queue here.
≥ 2 connection objects of something are added in #conns which had to be loaded serially as part of the loading process uses Expect->spawn
Multiple Worker threads are invoked, and each thread given a single $conns[$i] object & reference to the shared \#work_queue.
The worker threads safely removes a single item from #work_queue and performs some processing through its connection object, after which it picks up the next available item from #work_queue.
When this #work_queue is empty all the threads will shutdown safely
Now, the problem is that the loading phase is taking too long in many cases. But due to the use of Expect->spawn, parallel loading of #conns is possible only on a separate process & not on a thread.
Please suggest a good way to achieve the above scenario using fork. Or, even better if there is a way to use Expect->spawn with threads. (UNIX/LINUX only)
See Is it possible to use threads with Expect?
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'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...)");
}];