Javascript - Thread, Asymchronism, Ticks

Asked

Viewed 432 times

9

Situation

Studying on Thread, I understood that they are lines of execution within a process. Studying on Assincronismo em javascript, I understood that it does not support multiple Thread, but has a loop de eventos.
Making an analogy with C would be a memory with addresses, which runs sequentially each address, so when defining a setTimeout({function}, {time}), would be the same as setar {Function} at the address {team} to be executed.

However as @bfavaretto said in his reply, does not want to say that will execute in {team}, but in the next moment loop de eventos be free.

Testing

(function(){
    var start = null;

    var checkTicks = function(){
        start = new Date();         // SETA start COM DATA CORRENTE
        var s = start.getSplitDate();
        start = new Date(s['year'],s['month'],s['day'],s['hours'],s['minutes'],s['seconds']);

        setTimeout(showDiff, 1000); // DEFINE FUNÇÃO A SER EXECUTADA APOS 1s
        loop();                     // CHAMADO DE LOOP QUE DEVE DEMORAR 5s
    }

    var loop = function(){
        var stop = false;
        while(!stop){
            var current = new Date();
            var s = current.getSplitDate();
            current = new Date(s['year'], s['month'], s['day'], s['hours'], s['minutes'], s['seconds']);

            if(betweenDates(current.toTimestamp(), start.toTimestamp(), 's') > 5){ // SO PARA APOS DIFF DE 5s
                stop = true;
            }
        }
    }

    var showDiff = function(){
        var current = new Date();
        var s = current.getSplitDate();
        current = new Date(s['year'],s['month'],s['day'],s['hours'],s['minutes'],s['seconds']);

        console.log(start.toTimestamp());
        console.log(current.toTimestamp());

        console.log(betweenDates(current.toTimestamp(), start.toTimestamp(), 's')); // EXIBE DIFERENCA ENTRE start E current
    }

    checkTicks(); // INICIO O PROCESSO
})();

Console result

6

Doubt

  • Why the result was 6 in view of the command setTimeout(showDiff, 1000); defined showDiff to be executed in 1s?
  • The loop de eventos was occupied by 5s, showDiff should not be executed immediately after?

Editing

Talking to @bfavaretto again the logic had some inconsistencies because not taken into account the milliseconds of the Date object, to solve this set twice o the variable, in the second without the milliseconds, passing only the relevant values.

Auxiliary

betweenDates

	function betweenDates(d1, d2, diff, returnLiteral){
	
		d1 		= d1.split(' ');	// Divide o timestamp em data e hora
		d1[0]	= d1[0].split('-');	// Separa as variacoes da data
		d1[1]	= d1[1].split(':');	// Separa as variacoes da hora
		d1		= d1[0].concat(d1[1]); // concatena os dois conteudos formando um array unico.
	
		d1 = new Date(d1[0],d1[1],d1[2],d1[3],d1[4],d1[5]); // gera o objeto date
		d1 = Date.UTC(d1.getFullYear(), d1.getMonth(), d1.getDate(), d1.getHours(), d1.getMinutes(), d1.getSeconds()); // retona o time UTC corespondente da data.
		
		d2 		= d2.split(' ');
		d2[0]	= d2[0].split('-');
		d2[1]	= d2[1].split(':');
		d2		= d2[0].concat(d2[1]);
	
		d2 = new Date(d2[0],d2[1],d2[2],d2[3],d2[4],d2[5]);
		d2 = Date.UTC(d2.getFullYear(), d2.getMonth(), d2.getDate(), d2.getHours(), d2.getMinutes(), d2.getSeconds());
		
		var dDiff = d2 - d1; // calcula a diferenca entre as datas
		
		var out = {
			'y' : dDiff/1000/60/60/24/30/12,	// calculo para ano
			'm' : dDiff/1000/60/60/24/30,		// calculo para mes
			'd' : dDiff/1000/60/60/24,			// calculo para dia
			'h' : dDiff/1000/60/60,				// calculo para hora
			'i' : dDiff/1000/60,				// calculo para minuto
			's' : dDiff/1000/1					// calculo para segundo
		};
	
		out = Math.floor(out[diff]);	// Saida (inteiro do calculo)
		
		// Retorno
		if(out < 0 && !returnLiteral){
			return out*-1;
		}else{
			return out;
		}
	}

Date.prototype.getSplitDate

	Date.prototype.getSplitDate = function(){
		var day		= this.getDate();
		var month	= this.getMonth();
		var year	= this.getFullYear();
	
		var hours	= this.getHours();
		var minutes	= this.getMinutes();
		var seconds	= this.getSeconds();
	
		var o = {};
		o['day']	= day;
		o['month']	= month;
		o['year']	= year;
	
		o['hours']	= hours;
		o['minutes']= minutes;
		o['seconds']= seconds;
	
		return o;
	}

Date.prototype.toTimestamp

	Date.prototype.toTimestamp = function(short){
	
		var o = this.getSplitDate();
	
		var date = '####-##-## ##:##:##';
	
		date = o['year'].toString().lpad(0,4).mask(date);
		date = o['month'].toString().lpad(0,2).mask(date);
		date = o['day'].toString().lpad(0,2).mask(date);
	
		date = o['hours'].toString().lpad(0,2).mask(date);
		date = o['minutes'].toString().lpad(0,2).mask(date);
		date = o['seconds'].toString().lpad(0,2).mask(date);
	
		if(short){
			date = date.split(' ');
			return date[0];
		}else{
			return date;
		}
	}

String.prototype.Mask

	String.prototype.mask = function(mask){
		var value = onlyNumber(this);
	
		for(var i = 0; i <= mask.substrCount('#'); i++){
	
			if(typeof(value[i]) === 'undefined'){
				break;
			} 
	
			var k = mask.indexOf('#');
			mask = mask.split('');
			mask[k] = value[i];
			mask = mask.join('');
		}
	
		return mask;
	}

  • @bfavaretto, if possible would like your analysis.

  • What you have here: betweenDates. Could put the contents of this method also?

  • @Emirmarques is a great method, I believe have no relevance to this issue, what it does is basically compares two string format timestamp and pick up the difference in seconds. But if you want to see the method, because you may be interested, I assemble a question about and put as answer.

  • Could be the rounding of the betweenDates, No? Maybe I did 5.x.

  • @bfavaretto really has a Math.floor, but how is second ends up becoming whole, anyway. I edited , putting the function

  • What is .toTimestamp()?

  • And when you use betweenDates(current.toTimestamp(), start.toTimestamp(), 's') the argument diff within the function betweenDates it’s gonna be a string... that’s what you want?

  • @Sergio I think now has all the functions involved, as for the diff, yes a string

Show 3 more comments

3 answers

5


I think the best way to clarify this problem is to highlight the difference between competition and parallelism and the difference between cooperative and preemptive.

In parallel computing you have several things running at the same time (literally, on multiple processors) but not necessarily these computations will interact with each other.

If you are running concurrent computations, there is more than one "run line" running at a given time but it may be that they are running on a single processor. The running line The wheel a little, then it pauses and the line B rotates a little, and so it goes.

Finally, in a situation where you have multiple lines of execution sharing a processor, it may be that this share is cooperative or preemptive.

  • In a situation cooperative the execution lines explicitly give up the processor. In Javascript this occurs every time you make an asynchronous system call, which returns the pro event loop control.
  • On the other hand, in a competitive situation preemptive the system can interrupt execution at any time. This is what happens with your operating system processes or in the traditional threads you already know.

Getting back to your problem, what happened is that the function loop It never returns control to the event loop. It’s a simple while and while will continue running until the stop condition is false. In the end you kind of implemented a spin lock.

One way to solve this problem is to put a timeout between each loop iteration.

function meuloop(){
    var current = new Date();
    if(betweenDates(current.toTimestamp(), start.toTimestamp(), 's') < 5){
        // Peça para o loop de eventos continuar o  "meu loop" assim que puder.
        // Dessa forma, o loop de eventos tem a oportunidade de
        // rodar outros eventos também.
        setTimeout(meuloop, 0);
    }else{
        console.log("acabou");
    }
}

BTW, in Node you can also use the function nextTick instead of a timeout with zero:

proccess.nextTick(meuloop)
  • 1

    Guy I found very interesting the terms and I will study more about, so with doing the proper tests. Only now I’m out of time. Thanks for the help.

  • In fact the problem is that I didn’t return control to the loop de eventos.

  • So, in Javascript, nothing runs parallel, but yes, alternately?

  • @Guilhermecostamilam: Yes. And in addition the competition is cooperative and not preemptive.

  • Is there any example of language that uses preemptive competition?

  • Threads usually use preemptive competition. For example, pthreads in C and Java threads.

Show 1 more comment

5

Its function betweenDates is very imprecise, it never uses millisecond information that objects of the type Date include. I did a test by slightly changing your code, and the result was 5.007 seconds:

(function(){
    var start = null;

    var checkTicks = function(){
        start = new Date();         // SETA start COM DATA CORRENTE
        setTimeout(showDiff, 1000); // DEFINE FUNÇÃO A SER EXECUTADA APOS 1s
        loop();                     // CHAMADO DE LOOP QUE DEVE DEMORAR 5s
    }

    var loop = function(){
        var stop = false;
        while(!stop){
            var current = new Date();
            if(betweenDates(current, start) > 5){ // SO PARA APOS DIFF DE 5s
                stop = true;
            }
        }
    }

    var showDiff = function(){
        var current = new Date();
        console.log(betweenDates(current, start)); // EXIBE DIFERENCA ENTRE start E current
    }

    checkTicks(); // INICIO O PROCESSO
})();

function betweenDates(d1, d2) {
    return (d1.getTime() - d2.getTime()) / 1000;
}

http://jsfiddle.net/vux13w4k/

  • When I rode betweenDate, I based myself in this, as for the matter of milliseconds, I know javascript works based on them, but it is not strange that there is a difference of 0.07, for solid data? if none of the dates have milliseconds how can there be such a difference? would be something related to this?

  • In my example, the dates include yes the milliseconds. I do not understand well what is not yet clear to you...

  • Yes, I was just about to comment

  • I’m still doing tests here, but it won’t include millimeters start = new Date(); var s = start.getSplitDate(); start = new Date(s['year'], s['month'], s['day'], s['hours'], s['minutes'], s['seconds']);

  • new Date().getTime() includes milliseconds (which are part of the internal value stored in the Date object).

  • I edited the question, now it will no longer include the milliseconds : D

  • I thought you didn’t understand why the 6 seconds, not your timeout wait until the end of the loop to run...

Show 2 more comments

-1

That video explains how an Event Loop works. An event loop is implemented during the video.

Loop de Eventos do Javascript

This is the code that you at the end of the video.

var fs = require('fs');

class Queue {
  constructor() {
    this.events = [];
  }

  waitForEvents() {
    return true;
  }

  pushEvent(event) {
    this.events.push(event);
  }

  processNextEvent() {
    if (this.events.length > 0) {
      var event = this.events[0];

      if (event.type === 'timeout') {
        if (Date.now() >= event.registeredTime + event.timeout) {
          this.events.shift();
          event.fn();
        }
      }

    }
  }
}

var queue = new Queue();

function setTimeout2(fn, timeout) {
  var event = {
    type: 'timeout',
    registeredTime: Date.now(),
    timeout: timeout,
    fn: fn
  };
  queue.pushEvent(event);
}

// ================
// Program

setTimeout2(function() {
  console.log('Timeout 1 ' + Date.now());
}, 1000);

setTimeout2(function() {
  console.log('Timeout 2 ' + Date.now());
}, 1000);

setTimeout2(function() {
  console.log('Timeout 3 ' + Date.now());

  setTimeout2(function() {
    console.log('Timeout 4 ' + Date.now());
  }, 2000);

  setTimeout2(function() {
    console.log('Timeout 5 ' + Date.now());
  }, 2000);
}, 1000);

setTimeout2(function() {
  console.log('Timeout do Javascript');
}, 2000);

fs.readFile('setTimeout.js', 'utf8', function(error, data) {
  console.log('Arquivo lido:');
  console.log(data);
});

console.log('Arquivo lido');

// ================

while (queue.waitForEvents()) {
  queue.processNextEvent();
}

Browser other questions tagged

You are not signed in. Login or sign up in order to post.