When is it appropriate to use Dispatchers.Unconfined vs EmptyCoroutineContext?
My use case is that I want to create an API for intercepting network calls. I want to provide an optional parameter to control what dispatcher the interception is executed on. For the default value of this parameter, should it be Dispatchers.Unconfined or EmptyCoroutineContext?
For the default value of this parameter, should it be Dispatchers.Unconfined or EmptyCoroutineContext?
Most of the time it is Dispatchers.Unconfined.
EmptyCoroutineContext has no elements in it, semantically it is a null object. Coroutine builders, such as launch, specify their behaviour for that case: If the context does not have any dispatcher nor any other ContinuationInterceptor, then Dispatchers.Default is used. Most of the time you should not use EmptyCoroutineContext as you don't use nulls or null objects.
Dispatchers.Unconfined is different: it executes coroutine immediately on the current thread and later resumes it in whatever thread called resume.
It is usually a good fit for things like intercepting regular non-suspending API or invoking coroutine-related code from blocking world callbacks.
Related
When would I choose to use Dispatchers.Unconfined? Is when it doesn't really matter where the coroutine should run? So you let the coroutine to choose the thread pool as it better suits?
And how does it differ from Dispatchers.Default? Is it that when running the Default dispatcher is always within a specific thread pool defined as the default one?
So you let the coroutine to choose the thread pool as it better suits?
That's not really how Unconfined works. The best way to understand it is that it is a "no-op" dispatcher that doesn't actually do any dispatch at all. Wherever you call continuation.resume(), that's where the coroutine resumes execution — within that very call. When the resume() call returns, it means the coroutine has either suspended again or completed.
In normal programming, you usually call continuation.resume() from a callback and it is not your code that runs the callback, so you don't actually have any control over the thread where your coroutine will resume. It is not advisable to use the Unconfined dispatcher when resuming from a callback provided by a library that is not under your control.
Unconfined is really a special-cased tool you can use when building a coroutine execution environment yourself, or in other custom scenarios. Basically, you should use it only when you are actively looking for a way to disable the normal dispatching mechanism.
The unconfined dispatcher is appropriate for coroutines which neither consume CPU time nor update any shared data (like UI) confined to a specific thread.
So, I'd use it in non-IO, UI or computation heavy situations basically :D.
I think the nunmber of use-cases for this is pretty low, but I'd think of an operation which isn't heavy, but still for some reason you'd like it to run on a different thread.
Here's a link for how it actually works.
Dispatchers.Default is really different, and it's mostly used for heavy CPU operations.
This is because, it actually dispatches works to a thread pool with a number of threads equal to the number of CPU cores, and it's at least 2. This way developers can leverage the full capacity of the cpu when doing heavy computational work.
i was wondering since both withContext and suspendCoroutine are suspend functions is there any difference betweeen them other then the fact that suspendCoroutine offers a continuation so you can control when it resumes or cancels if we use suspendCancellableCoroutine variation.
I would say both can be used to stop making callbacks (which is one advantage of coroutines). is there any major difference ?
Actually only suspendCoroutine can be used to translate a callback-based API into coroutines. withContext doesn't have the effect of suspending a coroutine, but temporarily changing its context (this is mainly about changing the dispatcher). The coroutine immediately continues in the other context and then comes back to the caller's context.
I am currently implementing code that uses macOS API for HTTP/HTTPs requests in a Delphi/Lazarus program.
The code runs in its own thread (i.e. not main/ui thread) and is part of a larger threading based crawler across Windows/Mac and Delphi/Lazarus. I try to implement the actual HTTP/S request part using the OS API - but handle e.g. processing and taking action upon HTTP headers myself.
This means I would like to keep using synchronous mode if possible.
I want the request to simply return to me what the server returns.
I do not want it to follow redirects.
I currently use sendSynchroniousRequest_returningResponse_error
I have tried searching Google, but it seems there is no way when using synchronous requests? That just seems a bit odd.
No, NSURLConnection's synchronous functionality is very limited, and was never expanded because it is so strongly discouraged. That said, it is technically possible to implement what you're trying to do.
My recollection, from having replaced that method with an NSURLSession equivalent once (to swizzle in a less leaky replacement for that method in a binary-only library), is that you need to basically write a method that uses a shared dictionary to store a semaphore for each NSURLSessionDataTask (using the data task as a key). Then, you set the semaphore's count to zero so that it will block immediately when you wait on it, asynchronously start an asynchronous request on the main thread, and then wait on the semaphore (in the current thread). In the asynchronous data task's completion handler block, you increment the semaphore, thus unblocking the calling thread.
The trick is to ensure that the session runs its callbacks on a thread OTHER than the current one (which is blocked waiting for the semaphore). So you'll need to dispatch_async into the main thread when you actually start the data task.
Ostensibly, if you supported converting the task into a download task or stream task in the relevant delegate method, you would also need to take appropriate action to update the shared dictionary as well, but I'm assuming you won't use that feature. :-)
What is the exact nature of the thread-unsafety of a JMS Session and its associated constructs (Message, Consumer, Producer, etc)? Is it just that access to them must be serialized, or is it that access is restricted to the creating thread only?
Or is it a hybrid case where creation can be distinguished from use, i.e. one thread can create them only and then another thread can be the only one to use them? This last possibility would seem to contradict the statement in this answer which says "In fact you must not use it from two different threads at different times either!"
But consider the "Server Side" example code from the ActiveMQ documentation.
The Server class has data members named session (of type Session) and replyProducer (of type MessageProducer) which are
created in one thread: whichever one invokes the Server() constructor and thereby invokes the setupMessageQueueConsumer() method with the actual creation calls; and
used in another thread: whichever one invokes the onMessage() asynchronous callback.
(In fact, the session member is used in both threads too: in one to create the replyProducer member, and in the other to create a message.)
Is this official example code working by accident or by design? Is it really possible to create such objects in one thread and then arrange for another thread to use them?
(Note: in other messaging infrastructures, such as Solace, it's possible to specify the thread on which callbacks occur, which could be exploited to get around this "thread affinity of objects" restriction, but no such API call is defined in JMS, as far as I know.)
JMS specification says a session object should not be used across threads except when calling Session.Close() method. Technically speaking if access to Session object or it's children (producer, consumer etc) is serialized then Session or it's child objects can be accessed across threads. Having said that, since JMS is an API specification, it's implementation differs from vendor to vendor. Some vendors might strictly enforce the thread affinity while some may not. So it's always better to stick to JMS specification and write code accordingly.
The official answer appears to be a footnote to section 4.4. "Session" on p.60 in the JMS 1.1 specification.
There are no restrictions on the number of threads that can use a Session object or those it creates. The restriction is that the resources of a Session should not be used concurrently by multiple threads. It is up to the user to insure that this concurrency restriction is met. The simplest way to do this is to use one thread. In the case of asynchronous delivery, use one thread for setup in stopped mode and then start asynchronous delivery. In more complex cases the user must provide explicit synchronization.
Whether a particular implementation abides by this is another matter, of course. In the case of the ActiveMQ example, the code is conforming because all inbound message handling is through a single asynchronous callback.
Let's say I'm writing a Spring web-service that gets called by an external application. That application requests data that I need to load from an external resource. Furthermore, the design has it that it calls my service more than once with different parameters. In other words, the user sitting in front of the application presses one button, which generates a bunch of requests to my web-service in a very short time frame.
My web-service parses the parameters and comes up with necessary requests to the external resource. The logic has it that it may cause calling the external resource with the same parameters over and over again, which makes this the ideal candidate for caching.
Example:
The user presses that one button in the application
Application initiates ten requests to my web-service
My web-service receives them in parallel
After analysing the parameters of all requests, overall I'd need to call the external resources 15 times, but the parameters are mostly equal and only show that three calls would be enough to serve the 15 intended calls.
However, one call to the external resource may take some time.
As far as I understand how Spring does caching it writes the result of a #Cachable method into the cache. Apparently this means that before it treats another invocation of that method with the same parameters as cache hit, it must have a result of a previous invocation. This means that it doesn't provide support for pending method calls.
I need something like "Hey, I just saw a method invocation with the same parameters a second ago, but I'm still waiting for the result of that invocation. While I can't provide a result yet, I will hold that new invocation and reuse the result for it."
What are my options? Can I make Spring do that?
You can't make Spring do that out-of-the-box for very good reasons. The bottom line is that locking and synchronizing is very hard using a specific cache implementation so trying to do that in an abstraction is a bit insane. You can find some rationale and some discussion here
There is a discussion of using ehcache's BlockingCache SPR-11540
Guava also has such feature but the cache needs to be accessed in a very specific way (using a callback) that the CacheInterceptor does not really fit. It's still our plan to try to make that work at some point.
Do not forget that caching must be transparent (i.e. putting it on and off only leads to a performance change). Trying to parse arguments and compute what call should be made to your web service has high chances to lead to side effects. Maybe you should cache things at a different place?