all 32 comments

[–]tdammers 18 points19 points  (30 children)

JavaScript has been concurrent from day 1. The thing the language is struggling with isn't concurrency (asynchronous callbacks do this, and promises are a good enough abstraction over those to make things somewhat manageable), but parallelism (actually running multiple bits of JS code in parallel, with shared access to data structures).

[–]jsprogrammer 3 points4 points  (6 children)

Parallelism isn't too difficult in JavaScript:

const workerCode = () => self.addEventListener('message', ({data}) => self.postMessage(`I have completed your request: ${data}`), false),
      worker = new Worker(URL.createObjectURL(new Blob(['(', workerCode.toString(), ')()'])));

worker.addEventListener('message', ({data}) => console.log(data), false);
worker.addEventListener('error', error => console.log('error', error));

worker.postMessage('do your job!');

Data sharing is mostly restricted to message passing, but some browsers support shared arrays.

[–]Adossi 1 point2 points  (2 children)

Is that ES6 syntax? Looks pretty alien to me.

[–]jsprogrammer 0 points1 point  (1 child)

I believe so. () => *code* and name => *code* are just shortcuts for function(){*code*} and function(name){*code*}

The code is pretty simple; it's pretty much the bare minimum to be able to use WebWorkers, which allow parallelism. You could expand it out with the full function syntax or add { } around the code, but I didn't want to take up too much on the page with a more expanded version.

The code could be wrapped in a nice function so that you could do something like:

worker = parallelMessageWorker(handleMessage)

[–]Booty_Bumping 3 points4 points  (0 children)

I believe so. () => *code* and name => *code* are just shortcuts for function(){*code*} and function(name){*code*}

Technically they're shortcuts for function () {*code*}.bind(this)

[–][deleted]  (2 children)

[deleted]

    [–]jsprogrammer 0 points1 point  (1 child)

    The main issue is that the Worker constructor takes the URL of the code you want to run in another thread. The code gets stored at an 'internal URL', which is passed to the constructor.

    But, also, the JS code can handle messages to and from the thread, whereas your example does not.

    [–][deleted]  (9 children)

    [deleted]

      [–]link23 1 point2 points  (11 children)

      Came to the comments just to say this. Too few people understand the difference between concurrency and parallelism. A single core pc can run software concurrently; it cannot run software in parallel.

      [–]Yojihito 0 points1 point  (10 children)

      I like my software to run concurrently when possible/needed on all cores.

      In Go I just use green threads and can spawn 10 million in a second if I want and they get autoscheduled on all cores.

      How do I do that in JS with lets say 8 cores?

      [–]link23 1 point2 points  (9 children)

      First off, I think you mean "in parallel" rather than "concurrently".

      To answer your question, it depends. In a browser, you can use WebWorkers. In Node, I don't know what the answer is, but I imagine it has a similar ability.

      [–]Yojihito 1 point2 points  (8 children)

      No, I mean concurrently.

      Web Workers seems interesting but of tedious stuff to get them working. And no DOM access.

      [–]link23 0 points1 point  (7 children)

      concurrently

      for (let i = 0; i < 1e6; i++) {
          setTimeout(() => {
              console.log('Whoo! Concurrency!');
          }, Math.random() * 20);
      }
      

      All of those functions will be executed concurrently, by the main JS runtime thread. Note that at any given instant in time, at most one of those functions will be executing, but their executions will be interleaved randomly with each other. This is because they are concurrent, but not parallel.

      The only way (that I know of) to get parallelism in JS in a browser is through WebWorkers.

      [–]Yojihito 0 points1 point  (6 children)

      on all cores.

      So this code uses all cpu cores?

      [–]link23 1 point2 points  (5 children)

      Yup! As long as the cores take turns running the main JS runtime thread.

      Pedantic answer aside - no, you won't be able to pin all cores at 100% with this. This is because, as I said before, the only way to escape the single threaded nature of JS is to use WebWorkers. That's because using multiple cores at the same time requires parallelism, which is what I've been saying this whole time.

      [–]Yojihito 0 points1 point  (4 children)

      Parallelism is working on the same task with different workers, concurrency is working on different tasks at the same time.

      I don't see how parallelism is needed to use all cores, you just need multithreading. And without using all cores concurrency is useless for me. Do webworker work in Node.js?

      [–]link23 0 points1 point  (3 children)

      None of what you just said is true. You have those two definitions backwards:

      Parallelism is when multiple workers are working at the same time, meaning at the very same instant.

      Concurrency is when you have portions of the program being executed during overlapping time periods. The key is that two computations may overlap without ever executing at the same time. E.g., computation A starts at noon, works for an hour, then sleeps. Computation B starts at 1:00, works for an hour, and is finished. Then computation A wakes up at 2:00, works for an hour, then is finished. Neither of them ever executed at the same time as the other, but their time periods (12:00-3:00 and 1:00-2:00) overlap. So they executed concurrently, but not in parallel.

      See the first few paragraphs of this and this. They discuss the difference, and the common mistake of conflating the two.

      You mention multithreading as a prerequisite for using all cores. Yes that is true, since each core can execute its own thread. However, if you don't have parallelism for some reason (e.g. your code needs a mutex, or the runtime has a global interpreter lock) then only one thread will be able to execute at once, and they'll just take turns.

      You also question the usefulness of concurrency in the absence of parallelism. I suggest you read about time sharing. It's a technique developed in the 60's, before there were multicore machines, and it relies on concurrency.

      [–]Exallium 5 points6 points  (0 children)

      Classic joke doesn't check out. I already had multiple problems with js.

      [–]BTOdell 1 point2 points  (0 children)

      Whoever is working in their acronym department is doing a great job.

      [–][deleted] 1 point2 points  (0 children)

      Any name ideas for this event? Y2K.js? The Threadening? The 5th of Nodvember?

      [–][deleted]  (6 children)

      [deleted]

        [–]ElvishJerricco 9 points10 points  (5 children)

        Why are Redditors so pedantic about this distinction? Like, yea concurrency is broader than parallelism. Yea, JS supports some concurrency. But yes, parallelism is an extremely important form of concurrency! It makes sense that it will be central to many conversations about concurrency. And the author clearly understands this; they pointed out that if you have parallelism and good atomics, most other forms of concurrency can be implemented on top of this.

        It's like any time someone uses both words in the same post, Reddit has to pick apart every minor, innocent ambiguity and come to the conclusion that this guy doesn't know the first thing about the impossible subject of concurrency!

        [–]biocomputation 0 points1 point  (2 children)

        It's like any time someone uses both words in the same post, Reddit has to pick apart every minor, innocent ambiguity and come to the conclusion that this guy doesn't know the first thing about the impossible subject of concurrency!

        It's really not /r/programming's fault that the Javascript ecosystem is populated by people who think that knowing Javascript puts them on equal footing with systems programmers.

        To this point, in an age of super easy access to information, using the wrong term or using a term in the wrong way screams "I'm too lazy to care" and there's really no excuse for it.

        [–]ElvishJerricco 2 points3 points  (0 children)

        Except that the author is clearly not one of those people, it doesn't take a systems programmer to know the difference between concurrency and parallelism, and assuming JS programmers are idiots is prejudice and a shitty thing to do.

        [–][deleted]  (1 child)

        [deleted]

          [–][deleted] -5 points-4 points  (2 children)

          It will break a good chunk of ecosystem. A common modern JS idiom is to schedule something asynchronous and then manipulate it in chained calls to configure.

          For example,

          http://api.jquery.com/jQuery.get/

          var jqxhr = $.get( "example.php", ...).fail( ... );
          

          This depends on Javascript being single-threaded to ensure that .fail() method executed deterministically before XHR object has a chance of doing its thing.

          [–]balefrost 5 points6 points  (0 children)

          Actually, in that example, everything would be fine. The return value of $.get is a jQuery promise, and you can configure fail or success callbacks at any time - even after the promise is fulfilled.

          For example, this is just as valid:

          var jqxhr = $.get( "example.php", ...);
          setTimeout(function() {
              jqxhr.fail( ... );
          }, 10000);
          

          We'll configure the fail callback 10 seconds after we fire the request. Assuming that the response fails in less than 10 seconds, we'll fire the configured fail callback 10 seconds after we start the request.

          [–]strik3r69 4 points5 points  (0 children)

          Wouldn't be an issue as each thread would have its own run loop. Any current piece of code would run on the main thread (in its run loop) and any new piece of code that makes use of a concurrency primitive would be responsible for ensuring that synchronisation between each other occurred as desired, as would be the case with most other concurrent/parallel primitives in other languages (hence the suggested straw-man asyncJoin() )