I just started learning about Play framework lately and really like it so far.
There is just one thing that isn't clear to me. I'm a Java developer, with an blocking
and multi-threaded way of thinking so async programming is a little new to me.
So, Play framework uses an asynchronous WS API which doesn't block thread that calls it, nor
it blocks or spawns any other thread. When doing some async programming usually you have
to spawn a new thread and then make a WS call so you don't block your main thread. So my question here is how does Play's WS API manages to do async call to a web service without blocking current thread and without spawning a new one? Does it fire a request and then the main thread every once in a little checks if there is a Response available in the Future object? I'm aware of how to use it but I want to know what's the deal "under the hood". How would it be implemented in Scala? A simple example if possible would be a nice help.
Thanks in advance and best regards!
Under the hood play uses async-http-client which is based on NIO. A request will be dispatched and when the server responds, a callback (in this case the completion of the future) will be executed on a thread from the threadpool. This way no thread has to be blocked.
Play uses an "execution context", which is typically a thread pool, as described in the documentation:
It’s important to understand which thread code runs on with futures.
In the two code blocks above, there is an import on Plays default
execution context. This is an implicit parameter that gets passed to
all methods on the future API that accept callbacks. The execution
context will often be equivalent to a thread pool, though not
necessarily.
So no new threads are spawned, but only because there is already a pool of threads available for such work.
Related
I have a Scala Play application and one of the controllers fires a Future which does some logging. I have a simple call back function which executes when the Future completes.
I have written a test to check whether this logging happens. The rough logic is as follows:
feature{
scenario{
Given()
// set up the call
When()
// make a FakeRequest via reverse routing - logging will done in a separate thread via a Future
Then()
Thread.sleep(50) // sleep to allow logging to finish
// check if the logging has been done
The issue is the Thread.sleep. I have added that call in to block the main testing thread in order to give enough time to elapse for the Future which does the logging in a separate thread to complete before actually doing the checks to see if the logging has been done.
My question is whether there is a better way to do this? In reality if my application is running and the logging is taking an inordinate amount of time, then the main thread which governs the application will not terminate until the Future that does the logging in a separate thread finishes. So I don't see a problem of putting in the Thread call above to simulate that. But I just want to confirm if this is correct.
For me, there is absolutely no other way than to do this. If I try to replicate how the app behaves in reality with my test, then the main thread for the test should complete and terminate even though the future for the logging is still going on; there is no call back in the test and neither should there be.
Assuming you're using ScalaTest ; you can use whenReady construct ; which periodically inspects the passed future, until it is either ready or the configured timeout has been surpassed;
see
http://www.artima.com/docs-scalatest-2.0.M5/org/scalatest/concurrent/Futures.html
http://doc.scalatest.org/2.0/index.html#org.scalatest.concurrent.ScalaFutures
In the old days, when each request to a web application was handled by one thread, it was fairly easy to understand the logs. One could, for example, use a servlet filter to name the thread that was handling a request with some sort of request id. This request id then could be output in the logs. In this world, a simple grep was all it took to collect the log lines for a given request.
In my current position, I'm building web applications with Scala (we're using Scalatra but that isn't specifically relevant to my question). Each request creates a scala.concurrent.Future and is then parked until that future has completed. The important bit here is that the thread that actually handles the business logic is different from the thread that handled the request which is different (I think) from the thread that completes the request and so the context of that request is lost during processing. The business logic can log all it likes but it is hard to associate that logging with the specific request it relates to.
Now from the standpoint of supporting my web services in production, the old approach was great and I'd like to come up with something similar for my asynchronous services. I've been trying to come up with a way to do it but have come up empty. That is, I haven't come up with anything nearly as light weight as the old, name-the-thread model. Does the Stack Overflow crowd have any suggestions?
Thanks
As you have written, assign an id to each request, and pass that to the business logic function. You can also do this with implicit parameter, so your code won't be cluttered.
This should be possible with MDC logging available with SLF4j which uses Thread local storage to store the context of the each request.
Also you will have to create a MDC Context Propagating execution context, to move the context across threads.
This post describes it well:
http://code.hootsuite.com/logging-contextual-info-in-an-asynchronous-scala-application/
I want to make a class which as long as an instance of it is alive, keeps a thread (worker) going and when someone calls a method on it - performTaskWithData:(NSData*)data - then it should process this data in its worker thread.
If additional data is sent while an operation is taking place, then this new data/operation should be queued until the previous processing is done.
I need each instance of this helper class to hold one single worker thread (i.e. the same thread should handle all the processing).
How should I go about doing this?
NSRunLoop? Synchronize access to data block being passed?
Starting in iOS4, Grand Central Dispatch provides by far the simplest and most powerful interface to multithreaded programming.
If you're a registered developer, go watch some of the WWDC videos from 2010 about it. It's intimidating at first, but it's actually really simple and good.
You can do this directly with NSThreads and run loops. However, I would consider using NSOperationQueues, one per instance of your class and set the maximum concurrency of the queue to 1. Your performTaskWithData: would simply add a new instance of a subclass of NSOperation to the queue and that's it.
I have a complex sync job that does several asyncronous calls for content over HTTP. Each time this content is received, it asks for the next bit and so on. These are all daisey-chained in a big over-all sync job with data on the server.
There are probably 12 steps in this job chain. It seems to get stuck after around the 5th async request, the request never comes back and it hangs for ever waiting for it. I think it may have to do with too many threads being spawned because if I fire off the one it hangs at at the beginning it returns fine.
In the way I imagine it in my head, the main thread asks for async content a. When it comes back in its own asynchronous time it spawns a new thread which then asks for aync content b. When it comes back in its own sweet time it spawns a new thread which then asks for content c. Isn't a new thread being created everytime an async request returns a result?
Am I daisy-chaining these requests right? I was quite good at threads in Java development but I'm a bit confused on how they work in Obj-C. Do I need to use a Thread pool of say 3 threads and reuse these?
Sorry for the high-level question but I'm sure some experts can help clear the cloud of mystery around this.
NSOperationQueues are built on top of Grand Central Dispatch. If you need precise control over order of operations and the ability to dispatch synchronous requests you might want to use GCD directly. Using either, you don't really need to worry about thread creation/management. You simply queue your operations as needed by your app.
The Apple docs are fine on this IMHO but you can find a number of tutorials out there.
[EDIT: added link to Apple docs]
http://developer.apple.com/library/ios/#documentation/General/Conceptual/ConcurrencyProgrammingGuide/Introduction/Introduction.html
Is there any way I can kill a thread spawn through:
[NSThread detachNewThreadSelector:#selector(serverFetchInThread) toTarget:self withObject:nil];
The scenario I am working on is that in my main thread I am letting user enter data in my search bar and what ever user is typing I need to send to server for searching in a separate thread. Now, if user changes his selection by deleting old data and entering new data I do not want the previous thread to waste its time, kill it and spawn a new thread with new data.
Be there any other better way to handle this situation, please guide me.
No, there is no way to kill a thread from another thread. And for good reason as there is no way to do so in a fashion where the targeted thread is killed without risk of crashing the app.
To directly answer your question; you need to have some kind of a flag that indicates to the thread that it should stop doing whatever it is doing and exit.
However, a couple of questions are raised by your question:
First, why are you using threads and not using GCD? Concurrency via GCD or NSOperation is the generally recommended way to solve such problems.
Secondly, if you are talking to a server, are you using HTTP (most of the time, that is the case)? If so, why not directly use the asynchronous features of NSURL and friends?
Have a good look at using NSOperationQueue.
You can subclass NSOperation it to wrap up your server communications, and even make that queue serial (maximum operations = 1).
If a server operation is not yet finished and user has generated more input, you can cancel the existing one, and add the new one.
Due to the effect of the NSOperation wrapping your connection, you can just use the simple synchronous version and keep the connection handling very straightforward.
Also worth mentioning is compatibility. I would prefer to use GCD and blocks, but for compatibility, NSOperationQueue is required.