IT

자바 스크립트와 스레드

lottoking 2020. 7. 5. 07:48
반응형

자바 스크립트와 스레드


JavaScript에서 멀티 스레딩을 수행 할 수있는 방법이 있습니까?


최신 지원 정보는 http://caniuse.com/#search=worker참조 하십시오 .

다음은 2009 년 경 지원 상태입니다.


Google에 제공하려는 단어는 JavaScript Worker Threads입니다.

Gears 외에도 현재 사용할 수있는 것이 없지만이를 구현하는 방법에 대한 많은 이야기가 있으므로 미래의 대답이 의심 할 여지 없이이 질문을 보았습니다.

Gears 관련 문서는 다음과 같습니다. WorkerPool API

WHATWG에는 작업자 스레드에 대한 초안 권장 사항이 있습니다. 웹 작업자

그리고 Mozilla의 DOM Worker Threads도 있습니다.


업데이트 : 2009 년 6 월, JavaScript 스레드에 대한 브라우저 지원 상태

Firefox 3.5 에는 웹 워커가 있습니다. 웹 워커의 데모를보고 싶다면 :

Firefox에 Gears 플러그인을 설치할 수도 있습니다.

Safari 4WebKit 야간 에는 작업자 스레드가 있습니다.

Chrome 에는 Gears가 내장되어 있으므로 사용자의 확인 메시지가 필요하지만 스레드를 수행 할 수 있습니다 (Gears 플러그인이 설치된 모든 브라우저에서 작동하지만 웹 작업자에게 다른 API를 사용함).

  • Google Gears WorkerPool 데모 (IE는 상호 작용을 차단할 정도로 느리게 실행되지만 Chrome 및 Firefox에서 테스트하기에는 너무 빨리 실행되므로 좋은 예가 아님)

IE8IE9 는 Gears 플러그인이 설치된 스레드 만 수행 할 수 있습니다.


JavaScript에서 멀티 스레딩 및 비동기를 수행하는 다른 방법

HTML5 JavaScript 이전에는 페이지 당 하나의 스레드 만 실행할 수있었습니다.

와 비동기 실행 시뮬레이션 일부 해키 방법 있었다 수율은 , setTimeout(), setInterval(), XMLHttpRequest또는 이벤트 핸들러 (예와 본 게시물 마지막 참조 수율setTimeout()).

그러나 HTML5에서는 이제 Worker Threads를 사용하여 함수 실행을 병렬화 할 수 있습니다. 다음은 사용 예입니다.


실제 멀티 스레딩

멀티 스레딩 : JavaScript 작업자 스레드

HTML5 에는 Web Worker Threads가 도입되었습니다 ( 브라우저 호환성 참조 ).
참고 : IE9 및 이전 버전은이를 지원하지 않습니다.

이 작업자 스레드는 페이지 성능에 영향을주지 않으면 서 백그라운드에서 실행되는 JavaScript 스레드입니다. Web Worker 에 대한 자세한 내용은 설명서 또는 이 자습서를 참조하십시오 .

다음은 MAX_VALUE로 계산되고 현재 계산 된 값을 페이지에 표시하는 3 개의 Web Worker 스레드가있는 간단한 예입니다.

//As a worker normally take another JavaScript file to execute we convert the function in an URL: http://stackoverflow.com/a/16799132/2576706
function getScriptPath(foo){ return window.URL.createObjectURL(new Blob([foo.toString().match(/^\s*function\s*\(\s*\)\s*\{(([\s\S](?!\}$))*[\s\S])/)[1]],{type:'text/javascript'})); }

var MAX_VALUE = 10000;

/*
 *	Here are the workers
 */
//Worker 1
var worker1 = new Worker(getScriptPath(function(){
    self.addEventListener('message', function(e) {
        var value = 0;
        while(value <= e.data){
            self.postMessage(value);
            value++;
        }
    }, false);
}));
//We add a listener to the worker to get the response and show it in the page
worker1.addEventListener('message', function(e) {
  document.getElementById("result1").innerHTML = e.data;
}, false);


//Worker 2
var worker2 = new Worker(getScriptPath(function(){
    self.addEventListener('message', function(e) {
        var value = 0;
        while(value <= e.data){
            self.postMessage(value);
            value++;
        }
    }, false);
}));
worker2.addEventListener('message', function(e) {
  document.getElementById("result2").innerHTML = e.data;
}, false);


//Worker 3
var worker3 = new Worker(getScriptPath(function(){
    self.addEventListener('message', function(e) {
        var value = 0;
        while(value <= e.data){
            self.postMessage(value);
            value++;
        }
    }, false);
}));
worker3.addEventListener('message', function(e) {
    document.getElementById("result3").innerHTML = e.data;
}, false);


// Start and send data to our worker.
worker1.postMessage(MAX_VALUE); 
worker2.postMessage(MAX_VALUE); 
worker3.postMessage(MAX_VALUE);
<div id="result1"></div>
<div id="result2"></div>
<div id="result3"></div>

세 개의 스레드가 동시성으로 실행되고 현재 값을 페이지에 인쇄하는 것을 볼 수 있습니다. 그들은 분리 된 스레드로 백그라운드에서 실행되기 때문에 페이지를 고정시키지 않습니다.


멀티 스레딩 : 여러 iframe 사용

이를 달성하는 또 다른 방법은 여러 개의 iframe 을 사용하는 것입니다. 각 iframe 은 스레드를 실행합니다. 우리는 줄 수있는 iframe이 URL과에 의해 일부 매개 변수 iframe이이 결과를 얻고 (뒷면을 인쇄하기 위해 자신의 부모와 통신 할 수 iframe이이 같은 도메인에 있어야합니다).

이 예제는 모든 브라우저에서 작동하지 않습니다! iframe은 일반적으로 기본 페이지와 동일한 스레드 / 프로세스로 실행되지만 Firefox와 Chromium은 다르게 처리하는 것처럼 보입니다.

코드 스 니펫은 여러 HTML 파일을 지원하지 않으므로 여기에 다른 코드를 제공합니다.

index.html :

//The 3 iframes containing the code (take the thread id in param)
<iframe id="threadFrame1" src="thread.html?id=1"></iframe>
<iframe id="threadFrame2" src="thread.html?id=2"></iframe>
<iframe id="threadFrame3" src="thread.html?id=3"></iframe>

//Divs that shows the result
<div id="result1"></div>
<div id="result2"></div>
<div id="result3"></div>


<script>
    //This function is called by each iframe
    function threadResult(threadId, result) {
        document.getElementById("result" + threadId).innerHTML = result;
    }
</script>

thread.html :

//Get the parameters in the URL: http://stackoverflow.com/a/1099670/2576706
function getQueryParams(paramName) {
    var qs = document.location.search.split('+').join(' ');
    var params = {}, tokens, re = /[?&]?([^=]+)=([^&]*)/g;
    while (tokens = re.exec(qs)) {
        params[decodeURIComponent(tokens[1])] = decodeURIComponent(tokens[2]);
    }
    return params[paramName];
}

//The thread code (get the id from the URL, we can pass other parameters as needed)
var MAX_VALUE = 100000;
(function thread() {
    var threadId = getQueryParams('id');
    for(var i=0; i<MAX_VALUE; i++){
        parent.threadResult(threadId, i);
    }
})();

멀티 스레딩 시뮬레이션

단일 스레드 : setTimeout ()을 사용하여 JavaScript 동시성을 에뮬레이션

'순진한'방법은 다음 setTimeout()과 같이 함수를 차례로 실행하는 것입니다 .

setTimeout(function(){ /* Some tasks */ }, 0);
setTimeout(function(){ /* Some tasks */ }, 0);
[...]

그러나이 방법 각 작업이 하나씩 실행되므로 작동하지 않습니다 .

다음과 같이 함수를 재귀 적으로 호출하여 비동기 실행을 시뮬레이션 할 수 있습니다.

var MAX_VALUE = 10000;

function thread1(value, maxValue){
    var me = this;
    document.getElementById("result1").innerHTML = value;
    value++;
  
    //Continue execution
    if(value<=maxValue)
        setTimeout(function () { me.thread1(value, maxValue); }, 0);
}

function thread2(value, maxValue){
    var me = this;
    document.getElementById("result2").innerHTML = value;
    value++;
	
    if(value<=maxValue)
        setTimeout(function () { me.thread2(value, maxValue); }, 0);
}

function thread3(value, maxValue){
    var me = this;
    document.getElementById("result3").innerHTML = value;
    value++;
	
    if(value<=maxValue)
        setTimeout(function () { me.thread3(value, maxValue); }, 0);
}

thread1(0, MAX_VALUE);
thread2(0, MAX_VALUE);
thread3(0, MAX_VALUE);
<div id="result1"></div>
<div id="result2"></div>
<div id="result3"></div>

보시다시피이 두 번째 방법은 매우 느리고 메인 스레드를 사용하여 기능을 실행하기 때문에 브라우저를 정지시킵니다.


단일 스레드 : 수율로 JavaScript 동시성을 에뮬레이션

Yield ECMAScript 6 의 새로운 기능으로 Firefox 및 Chrome의 가장 오래된 버전에서만 작동합니다 (Chrome에서는 chrome : // flags / # enable-javascript-harmony에 나타나는 Experimental JavaScript 를 활성화해야 함).

yield 키워드는 생성기 함수 실행을 일시 중지시키고 yield 키워드 다음의 표현식 값은 생성자의 호출자에게 반환됩니다. return 키워드의 생성기 기반 버전으로 생각할 수 있습니다.

생성기를 사용하면 함수 실행을 일시 중단하고 나중에 다시 시작할 수 있습니다. 발전기는 trampolining 이라는 기술로 기능을 예약하는 데 사용할 수 있습니다 .

예를 들면 다음과 같습니다.

var MAX_VALUE = 10000;

Scheduler = {
	_tasks: [],
	add: function(func){
		this._tasks.push(func);
	},	
	start: function(){
		var tasks = this._tasks;
		var length = tasks.length;
		while(length>0){
			for(var i=0; i<length; i++){
				var res = tasks[i].next();
				if(res.done){
					tasks.splice(i, 1);
					length--;
					i--;
				}
			}
		}
	}	
}


function* updateUI(threadID, maxValue) {
  var value = 0;
  while(value<=maxValue){
	yield document.getElementById("result" + threadID).innerHTML = value;
	value++;
  }
}

Scheduler.add(updateUI(1, MAX_VALUE));
Scheduler.add(updateUI(2, MAX_VALUE));
Scheduler.add(updateUI(3, MAX_VALUE));

Scheduler.start()
<div id="result1"></div>
<div id="result2"></div>
<div id="result3"></div>


HTML5 "side-specs"를 사용하면 setTimeout (), setInterval () 등으로 더 이상 자바 스크립트를 해킹 할 필요가 없습니다 .

HTML5 & Friends는 자바 스크립트 웹 워커 사양을 소개합니다 . 스크립트를 비동기 적으로 독립적으로 실행하기위한 API입니다.

사양튜토리얼에 링크합니다 .


JavaScript에는 진정한 스레딩이 없습니다. JavaScript는 가단 언어이므로 일부를 에뮬레이트 할 수 있습니다. 여기입니다 예를 들어 내가 일전에 우연히 만났다는.


Javascript에는 진정한 멀티 스레딩이 없지만 setTimeout()비동기 AJAX 요청을 사용하여 비동기 동작을 얻을 수 있습니다 .

정확히 무엇을 달성하려고합니까?


다음은 자바 스크립트에서 멀티 스레딩 시뮬레이션 하는 방법입니다.

이제 3 개의 스레드를 만들어 숫자 추가를 계산하고 숫자를 13으로 나누고 숫자를 3에서 10000000000까지 나눌 수 있습니다.이 세 함수는 동시성이 의미하는 것과 동시에 실행할 수 없습니다. 그러나이 함수를 동시에 재귀 적으로 실행시키는 트릭을 보여 드리겠습니다 : jsFiddle

이 코드는 내 소유입니다.

신체 부위

    <div class="div1">
    <input type="button" value="start/stop" onclick="_thread1.control ? _thread1.stop() : _thread1.start();" /><span>Counting summation of numbers till 10000000000</span> = <span id="1">0</span>
</div>
<div class="div2">
    <input type="button" value="start/stop" onclick="_thread2.control ? _thread2.stop() : _thread2.start();" /><span>Counting numbers can be divided with 13 till 10000000000</span> = <span id="2">0</span>
</div>
<div class="div3">
    <input type="button" value="start/stop" onclick="_thread3.control ? _thread3.stop() : _thread3.start();" /><span>Counting numbers can be divided with 3 till 10000000000</span> = <span id="3">0</span>
</div>

자바 스크립트 부분

var _thread1 = {//This is my thread as object
    control: false,//this is my control that will be used for start stop
    value: 0, //stores my result
    current: 0, //stores current number
    func: function () {   //this is my func that will run
        if (this.control) {      // checking for control to run
            if (this.current < 10000000000) {
                this.value += this.current;   
                document.getElementById("1").innerHTML = this.value;
                this.current++;
            }
        }
        setTimeout(function () {  // And here is the trick! setTimeout is a king that will help us simulate threading in javascript
            _thread1.func();    //You cannot use this.func() just try to call with your object name
        }, 0);
    },
    start: function () {
        this.control = true;   //start function
    },
    stop: function () {
        this.control = false;    //stop function
    },
    init: function () {
        setTimeout(function () {
            _thread1.func();    // the first call of our thread
        }, 0)
    }
};
var _thread2 = {
    control: false,
    value: 0,
    current: 0,
    func: function () {
        if (this.control) {
            if (this.current % 13 == 0) {
                this.value++;
            }
            this.current++;
            document.getElementById("2").innerHTML = this.value;
        }
        setTimeout(function () {
            _thread2.func();
        }, 0);
    },
    start: function () {
        this.control = true;
    },
    stop: function () {
        this.control = false;
    },
    init: function () {
        setTimeout(function () {
            _thread2.func();
        }, 0)
    }
};
var _thread3 = {
    control: false,
    value: 0,
    current: 0,
    func: function () {
        if (this.control) {
            if (this.current % 3 == 0) {
                this.value++;
            }
            this.current++;
            document.getElementById("3").innerHTML = this.value;
        }
        setTimeout(function () {
            _thread3.func();
        }, 0);
    },
    start: function () {
        this.control = true;
    },
    stop: function () {
        this.control = false;
    },
    init: function () {
        setTimeout(function () {
            _thread3.func();
        }, 0)
    }
};

_thread1.init();
_thread2.init();
_thread3.init();

이 방법이 도움이 되길 바랍니다.


코드를 상태 머신으로 변환하여 효과적으로 스레딩을 에뮬레이트하는 컴파일러 인 Narrative JavaScript를 사용할 수 있습니다 . 단일 선형 코드 블록에 비동기 코드를 작성할 수있는 언어에 "yielding"연산자 ( '->'로 표기)를 추가하면됩니다.


The new v8 engine which should come out today supports it (i think)


Another possible method is using an javascript interpreter in the javascript environment.

By creating multiple interpreters and controlling their execution from the main thread, you can simulate multi-threading with each thread running in its own environment.

The approach is somewhat similar to web workers, but you give the interpreter access to the browser global environment.

I made a small project to demonstrate this.

A more detailed explanation in this blog post.


In raw Javascript, the best that you can do is using the few asynchronous calls (xmlhttprequest), but that's not really threading and very limited. Google Gears adds a number of APIs to the browser, some of which can be used for threading support.


If you can't or don't want to use any AJAX stuff, use an iframe or ten! ;) You can have processes running in iframes in parallel with the master page without worrying about cross browser comparable issues or syntax issues with dot net AJAX etc, and you can call the master page's JavaScript (including the JavaScript that it has imported) from an iframe.

E.g, in a parent iframe, to call egFunction() in the parent document once the iframe content has loaded (that's the asynchronous part)

parent.egFunction();

Dynamically generate the iframes too so the main html code is free from them if you want.


Javascript doesn't have threads, but we do have workers.

Workers may be a good choice if you don't need shared objects.

Most browser implementations will actually spread workers across all cores allowing you to utilize all cores. You can see a demo of this here.

I have developed a library called task.js that makes this very easy to do.

task.js Simplified interface for getting CPU intensive code to run on all cores (node.js, and web)

A example would be

function blocking (exampleArgument) {
    // block thread
}

// turn blocking pure function into a worker task
const blockingAsync = task.wrap(blocking);

// run task on a autoscaling worker pool
blockingAsync('exampleArgumentValue').then(result => {
    // do something with result
});

With HTML5 specification you do not need to write too much JS for the same or find some hacks.

One of the feature introduced in HTML5 is Web Workers which is JavaScript running in the background,independently of other scripts, without affecting the performance of the page.

It is supported in almost all browsers :

Chrome - 4.0+

IE - 10.0+

Mozilla - 3.5+

Safari - 4.0+

Opera - 11.5+

참고URL : https://stackoverflow.com/questions/30036/javascript-and-threads

반응형