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.
Related
Every Thread has its own RunLoop, how DispatchQueue interact with them? Is DispatchQueue using RunLoop to dispatch task to Thread or do it by another way?
Any thread can have a run loop, but, nowadays, in practice, only the main thread does.
When you create a thread manually, it will not have a run loop. When you call RunLoop.current, the name suggests that it is grabbing the thread’s run loop, suggesting that it always will have one. But in reality, when you call current, it will return the run loop if one is already there, and if not, it creates a RunLoop for you. As the docs say:
If a run loop does not yet exist for the thread, one is created and returned.
And if you do create a run loop, you have to spin on it yourself (as shown here; and that example is over-simplified). But we don’t do that very often anymore. GCD has rendered it largely obsolete.
At a high level, GCD has pools of worker threads, one pool per quality of service (QoS). When you dispatch something via GCD to any queue (other than targeting the main queue), it grabs an available worker thread of the appropriate QoS, performs the task, and when done, marks the worker thread as available for future dispatched tasks. No run loop is needed (or desired) for these worker threads.
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 have an application which uses some external library for analytics. Problem is that I suspect it does some things synchronously, which blocks my thread and makes watchdog kill my app after 10 secs (0x8badf00d code). It is really hard to reproduce (I cannot), but there are quite few cases "in the wild".
I've read some documentation, which suggested that instead creating another thread I should use run-loops. Unfortunately the more I read about them, the more confused I get. And the last thing i want to do is release a fix which will break even more things :/
What I am trying to achieve is:
From main thread add a task to the run-loop, which calls just one function: initMyAnalytics(). My thread continues running, even if initMyAnalytics() gets locked waiting for network data. After initMyAnalytics() finishes, it quietly quits and never gets called again (so it doesnt loop or anything).
Any ideas how to achieve it? Code examples are welcome ;)
Regards!
You don't need to use a run loop in that case. Run loops' purpose is to proceed events from various sources sequentially in a particular thread and stay idle when they have nothing to do. Of course, you can detach a thread, create a run loop, add a source for your function and run the run loop until the function ends. The same as you can use a semi-trailer truck to carry your groceries home.
Here, what you need are dispatch queues. Dispatch queues are First-In-First-Out data structures that run tasks asynchronously. In contrary to run loops, a dispatch queue isn't tied to a particular thread: the working threads are automatically created and terminated as and when required.
As you only have one task to execute, you don't need to create a dispatch queue. Instead you will use an existing global concurrent queue. A concurrent queue execute one or more tasks concurrently, which is perfectly fine in our case. But if we had many tasks to execute and wanted each task to wait for its predecessor to end, we would need to create a serial queue.
So all you have to do is:
create a task for your function by enclosing it into a Block
get a global queue using dispatch_get_global_queue
add the task to the queue using dispatch_async.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
initMyAnalytics();
});
DISPATCH_QUEUE_PRIORITY_DEFAULT is a macro that evaluates to 0. You can get different global queues with different priorities. The second parameter is reserved for future use and should always be 0.
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.
How does the actor model (in Akka) work when you need to perform I/O (ie. a database operation)?
It is my understanding that a blocking operation will throw an exception (and essentially ruin all concurrency due to the evented nature of Netty, which Akka uses). Hence I would have to use a Future or something similar - however I don't understand the concurrency model.
Can 1 actor be processing multiple message simultaneously?
If an actor makes a blocking call in a future (ie. future.get()) does that block only the current actor's execution; or will it prevent execution on all actors until the blocking call has completed?
If it blocks all execution, how does using a future assist concurrency (ie. wouldn't invoking blocking calls in a future still amount to creating an actor and executing the blocking call)?
What is the best way to deal with a multi-staged process (ie. read from the database; call a blocking webservice; read from the database; write to the database) where each step is dependent on the last?
The basic context is this:
I'm using a Websocket server which will maintain thousands of sessions.
Each session has some state (ie. authentication details, etc);
The Javascript client will send a JSON-RPC message to the server, which will pass it to the appropriate session actor, which will execute it and return a result.
Execution of the RPC call will involve some I/O and blocking calls.
There will be a large number of concurrent requests (each user will be making a significant amount of requests over the WebSocket connection and there will be a lot of users).
Is there a better way to achieve this?
Blocking operations do not throw exceptions in Akka. You can do blocking calls from an Actor (which you probably want to minimize, but thats another story).
no, 1 actor instance cannot.
It will not block any other actors. You can influence this by using a specific Dispatcher. Futures use the default dispatcher (the global event driven one normally) so it runs on a thread in a pool. You can choose which dispatcher you want to use for your actors (per actor, or for all). I guess if you really wanted to create a problem you might be able to pass exactly the same (thread based) dispatcher to futures and actors, but that would take some intent from your part. I guess if you have a huge number of futures blocking indefinitely and the executorservice has been configured to a fixed amount of threads, you could blow up the executorservice. So a lot of 'ifs'. a f.get blocks only if the Future has not completed yet. It will block the 'current thread' of the Actor from which you call it (if you call it from an Actor, which is not necessary by the way)
you do not necessarily have to block. you can use a callback instead of f.get. You can even compose Futures without blocking. check out talk by Viktor on 'the promising future of akka' for more details: http://skillsmatter.com/podcast/scala/talk-by-viktor-klang
I would use async communication between the steps (if the steps are meaningful processes on their own), so use an actor for every step, where every actor sends a oneway message to the next, possibly also oneway messages to some other actor that will not block which can supervise the process. This way you could create chains of actors, of which you could make many, in front of it you could put a load balancing actor, so that if one actor blocks in one chain another of the same type might not in the other chain. That would also work for your 'context' question, pass of workload to local actors, chain them up behind a load balancing actor.
As for netty (and I assume you mean Remote Actors, because this is the only thing that netty is used for in Akka), pass of your work as soon as possible to a local actor or a future (with callback) if you are worried about timing or preventing netty to do it's job in some way.
Blocking operations will generally not throw exceptions, but waiting on a future (for example by using !! or !!! send methods) can throw a time out exception. That's why you should stick with fire-and-forget as much as possible, use a meaningful time-out value and prefer callbacks when possible.
An akka actor cannot explicitly process several messages in a row, but you can play with the throughput value via the config file. The actor will then process several message (i.e. its receive method will be called several times sequentially) if its message queue it's not empty: http://akka.io/docs/akka/1.1.3/scala/dispatchers.html#id5
Blocking operations inside an actor will not "block" all actors, but if you share threads among actors (recommended usage), one of the threads of the dispatcher will be blocked until operations resume. So try composing futures as much as possible and beware of the time-out value).
3 and 4. I agree with Raymond answers.
What Raymond and paradigmatic said, but also, if you want to avoid starving the thread pool, you should wrap any blocking operations in scala.concurrent.blocking.
It's of course best to avoid blocking operations, but sometimes you need to use a library that blocks. If you wrap said code in blocking, it will let the execution context know you may be blocking this thread so it can allocate another one if needed.
The problem is worse than paradigmatic describes since if you have several blocking operations you may end up blocking all threads in the thread pool and have no free threads. You could end up with deadlock if all your threads are blocked on something that won't happen until another actor/future gets scheduled.
Here's an example:
import scala.concurrent.blocking
...
Future {
val image = blocking { load_image_from_potentially_slow_media() }
val enhanced = image.enhance()
blocking {
if (oracle.queryBetter(image, enhanced)) {
write_new_image(enhanced)
}
}
enhanced
}
Documentation is here.