Asynchronous processing with a single thread
Asked Answered
A

2

5

Even after reading http://krondo.com/?p=1209 or Does an asynchronous call always create/call a new thread? I am still confused about how to provide asynchronous calls on an inherently single-threaded system. I will explain my understanding so far and point out my doubts.

One of the examples I read was describing a TCP server providing asynch processing of requests - a user would call a method e.g. get(Callback c) and the callback would be invoked some time later. Now, my first issue here - we have already two systems, one server and one client. This is not what I mean, cause in fact we have two threads at least - one in the server and one on the client side.

The other example I read was JavaScript, as this is the most prominent example of single-threaded asynch system with Node.js. What I cannot get through my head, maybe thinking in Java terms, is this:If I execute the code below (apologies for incorrect, probably atrocious syntax):

function foo(){
    read_file(FIle location, Callback c) //asynchronous call, does not block
    //do many things more here, potentially for hours
}

the call to read file executes (sth) and returns, allowing the rest of my function to execute. Since there is only one thread i.e. the one that is executing my function, how on earth the same thread (the one and only one which is executing my stuff) will ever get to read in the bytes from disk?

Basically, it seems to me I am missing some underlying mechanism that is acting like round-robin scheduler of some sort, which is inherently single-threaded and might split the tasks to smaller ones or call into a multiothraded components that would spawn a thread and read the file in.

Thanks in advance for all comments and pointing out my mistakes on the way.

Update: Thanks for all responses. Further good sources that helped me out with this are here:

  1. http://www.html5rocks.com/en/tutorials/async/deferred/
  2. http://lostechies.com/johnteague/2012/11/30/node-js-must-know-concepts-asynchrounous/
  3. http://www.interact-sw.co.uk/iangblog/2004/09/23/threadless (.NET)
  4. http://ejohn.org/blog/how-javascript-timers-work/ (intrinsics of timers)
  5. http://www.mobl-lang.org/283/reducing-the-pain-synchronous-asynchronous-programming/
Abut answered 21/1, 2014 at 16:20 Comment(1)
There may or may not be a background thread implicitly started by a pending operation, but it's completely opaque and irrelevant to your JavaScript code which started the operation itself. The core event loop of the JavaScript thread in web browser (or NodeJS, FTM) is single-threaded.Fabio
P
3

The real answer is that it depends on what you mean by "single thread".

There are two approaches to multitasking: cooperative and interrupt-driven. Cooperative, which is what the other StackOverflow item you cited describes, requires that routines explicitly relinquish ownership of the processor so it can do other things. Event-driven systems are often designed this way. The advantage is that it's a lot easier to administer and avoids most of the risks of conflicting access to data since only one chunk of your code is ever executing at any one time. The disadvantage is that, because only one thing is being done at a time, everything has to either be designed to execute fairly quickly or be broken up into chunks that to so (via explicit pauses like a yield() call), or the system will appear to freeze until that event has been fully processed.

The other approach -- threads or processes -- actively takes the processor away from running chunks of code, pausing them while something else is done. This is much more complicated to implement, and requires more care in coding since you now have the risk of simultaneous access to shared data structures, but is much more powerful and -- done right -- much more robust and responsive.

Yes, there is indeed a scheduler involved in either case. In the former version the scheduler is just spinning until an event arrives (delivered from the operating system and/or runtime environment, which is implicitly another thread or process) and dispatches that event before handling the next to arrive.

Phenazine answered 21/1, 2014 at 16:30 Comment(2)
SO, in Java script, my calling to load a file from disk would be an event or series of events placed on the queue to be processed? But since that is the case, my code is not really the executing thread, since there can be only one thread, which is, in fact, the main loop thread pulling events of the queue only... So, if the main thread is doing event pulling, there must clearly be another thread that is scheduling those events iu.e. putting them in that queue, right?Abut
I'm not really a Javascript user so I can't answer that specifically. But remember, you've got a whole operating system behind you, plus the browser or other runtime environment that the Javascript is running in. Those have their own threads/processes timesharing with your Javascript, and asynchronous operations in your Javascript may be handed off to them.Phenazine
H
0

The way I think of it in JavaScript is that there is a Queue which holds events. In the old Java producer/consumer parlance, there is a single consumer thread pulling stuff off this queue and executing every function registered to receive the current event. Events such as asynchronous calls (AJAX requests completing), timeouts or mouse events get pushed on to the Queue as soon as they happen. The single "consumer" thread pulls them off the queue and locates any interested functions and then executes them, it cannot get to the next Event until it has finished invoking all the functions registered on the current one. Thus if you have a handler that never completes, the Queue just fills up - it is said to be "blocked".

The system has more than one thread (it has at least one producer and a consumer) since something generates the events to go on the queue, but as the author of the event handlers you need to be aware that events are processed in a single thread, if you go into a tight loop, you will lock up the only consumer thread and make the system unresponsive.

So in your example :

 function foo(){
    read_file(location, function(fileContents) {
        // called with the fileContents when file is read
    }     
    //do many things more here, potentially for hours
 }

If you do as your comments says and execute potentially for hours - the callback which handles fileContents will not fire for hours even though the file has been read. As soon as you hit the last } of foo() the consumer thread is done with this event and can process the next one where it will execute the registered callback with the file contents.

HTH

Heyduck answered 21/1, 2014 at 16:52 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.