top | item 8286162

Taming the Asynchronous Beast with CSP in JavaScript

147 points| jlongster | 11 years ago |jlongster.com | reply

29 comments

order
[+] craigching|11 years ago|reply
He mentions using CSP with JavaScript:

> It's safe to say that it's becoming quite popular (and validated) and I think we need to try it out in JavaScript.

To be clear, and he mentions that Clojure has core.async, it's been done in JavaScript (if you will) already via ClojureScript.

David Nolen has done a series of posts on it starting at [1].

[1] -- http://swannodette.github.io/2013/07/12/communicating-sequen...

EDIT: And I should have finished reading the post before posting this. He does mention David Nolen's series of posts on ClojureScript and core.async

[+] tracker1|11 years ago|reply
What would be nice as an addendum to this, especially with the likes of browserify and webpack for node and the browser would be a syntax to start an async channel in a new process/webworker...

    var ch = new echan('moduleName');
Where the moduleName would be a module that exports a single function that receives two channels.. in, and out for a request/response pattern. An "easy" level of abstraction here where the request/response is only going to pass what works with JSON.stringify/parse, removing circular references.

It could work really well for worker handlers... It only needs to be an abstraction around the csp interfaces, as well as the current implementations for web workers and forked processes in node.js

More advanced scenarios could use 0mq for passing a worker to multiple processes... all of that said, it's just an idea.

I think where this lines up very cleanly is as a means of communication with React and flux.

[+] BrianEatWorld|11 years ago|reply
My understanding of Javascript is that it is essentially single-threaded. Maybe I am mistaken, but if that is indeed the case, how does something like JS-CSP or Clojurescript's core.async accomplish concurrency? Has there been a change in the underlying Javascript? Is it just using tricks to make single-thread act like multi-thread?
[+] dminor|11 years ago|reply
Say you have:

  function one() {
    console.log("one");
    setTimeout(one, 1000);
  }
  
  function two() {
    console.log("two");
    setTimeout(two, 2000);
  }
  
  one();
  two();
They are executing concurrently, but never in parallel (since javascript is single threaded).

Now, how do you coordinate them if you need to? This is what CSP helps you do.

[+] arnarbi|11 years ago|reply
Short answer: Yes.

Concurrency does not necessarily mean parallelism (multi-threading). CSP-derived mechanisms provide abstractions for units-of-work to yield control to other units-of-work. Here, a unit of work is a function invocation, but it can be a block, a thread-like object etc. With such primitives it is fairly easy to build cooperative (as opposed to pre-emptive) concurrency mechanisms.

For a mature example, see e.g. http://www.stackless.com/

[+] craigching|11 years ago|reply
In the JavaScript "user space" you don't have access to threads (with the exception of web workers), but the JS engines themselves are multi-threaded and fully concurrent. This is why your UI doesn't freeze when doing XHR (assuming you're not doing synchronous XHR) and represents the need for elegantly handling asynchronicity.
[+] vfclists|11 years ago|reply
Why doesn't he state what CSP is upfront, requiring the reader to visit Wikipedia to know what it is?

Buzz words and acronyms are getting out of hand on the web.

[+] thesorrow|11 years ago|reply
How does this compare to FRP style ?
[+] jlongster|11 years ago|reply
It's more general than FRP so is better at stuff like simple async coordination (what most people use promises for). But you can easy do FRP-style stuff on top of channels, which is basically what transducers are. So they are closely related, but have different roots.
[+] neilellis|11 years ago|reply
You've got to wonder why exactly we still (in 2014) have to contort ourselves around a single threaded model. So that we end up with this level of complexity.

JavaScript is great with data but is becoming a monstrosity when it comes to concurrency.

Can we all stop and have a deep look at how other languages deal with concurrency. I have (like many of you) used many different languages and have played with several different concurrency models. The bottom line for me is that multiple threads + concurrency frameworks (i.e. no exposed concurrency primitives) are still the best solution.

I appreciate JavaScript is trying to avoid deadlocking etc. but in modern concurrency frameworks this just isn't an issue.

Seriously we're now contorting ourselves around dogma. Please browser folk, come up with a decent solution to save us all of this.

VOTED DOWN FOR HERESY :-)

[+] swannodette|11 years ago|reply
It's not clear to me that you actually read the article since a large part of it is about elegantly dealing with streams of UI events such as mouse movement without resorting to callbacks. Not sure how multithreading even applies here. But if you want to talk about multithreading the model described is exactly the one embraced by a new up and coming language called Go - it's users love this stuff precisely because it's more readable than writing code with explicit threads and concurrent queues.
[+] jlongster|11 years ago|reply
I think you've completely missed the point. CSP channels are in fact what are used for elegant parallelism on Clojure. The processes are backed by a thread-pool and can be run concurrently. Whether or not it's backed by real threads or not is completely opaque.
[+] Lerc|11 years ago|reply
What solution would you recommend? I have given this a lot of thought and have a few ideas. Is there a venue for discussing the problem and suggesting possible solutions?

In lieu of a decent forum. I'll drop my thoughts here.

I have felt that the fundamental problem with JavaScript is that it cannot pre-empt. Even with its concurrency of web workers the primary example they give shows the flaw inherent in their solution

http://www.whatwg.org/specs/web-apps/current-work/multipage/...

As a challenge, try and write a version of this worker that the owner page can switch between two number sequence algorithms(prime / Fibonacci for example). The only way you can do this is to rework the program until it's back to being a program beholden to events.

You could solve most of this with a pre-emption mechanism. Allow an additional way to respond to certain inputs by registering an interrupt instead of listening to an event.

    function myInterrupt(preEmptedState) {
        interruptCounter+=1;
        //do something useful here
        setExecutionState(preEmptedState);  //switch execution context back to pre-empted thread.
    }
The parameter to the interrupt function is the execution state of the thread that was pre-empted. This can be restarted at the end of the interrupt, stored for continuation at a later time (enabling blocking), or abandoned (effectively terminating the thread).

What this would need is:

An execution state object, possibly an opaque object.

addXXXInterruptHandler(interruptHandler) ;; XXX= Timer/Message/Input/etc.

setExecutionState(newState) ;; this function would not return, it would continue the new state.

createExecutionState(main) ;; generate a new execution state object ready to run the function main

triggerInterrupt(interruptType) ;; Allow a tread to trigger an interrupt upon itself.

If interrupts themselves are simply the running of a new execution state then TriggerInterrupt is just a special case of setInterruptState.

Having this as a core would allow a huge number of higher level constructs that would enable blocking functions, and sane interactions with running processes like web workers.

Yes, you would introduce the possibility of race conditions etc. but only if you actually used the new functionality. If you chose to leave it alone you would be on the old single eventy thready system that we know and hate.

It would also mean you could have someone write var x=0; while(x<10) {} without it killing all scripts.

[+] silon3|11 years ago|reply
If you add shared memory threads (like in c++, c#, java) to Javascript, I'm disabling it forever.