最近在写课设--操作系统
要写关于多线程的东西,题目都比较简单
但是c、java图形界面真是很麻烦的事情
于是,我就想到了我的老朋友,js
说干就干!
但是都说js是单线程的,如何才能模拟多线程效果呢?
多线程是什么效果?
度娘说
多线程(英语:multithreading),是指从软件或者硬件上实现多个线程并发执行的技术。具有多线程能力的计算机因有硬件支持而能够在同一时间执行多于一个线程,进而提升整体处理性能。具有这种能力的系统包括对称多处理机、多核心处理器以及芯片级多处理(Chip-level multithreading)或同时多线程(Simultaneous multithreading)处理器。[1] 在一个程序中,这些独立运行的程序片段叫作“线程”(Thread),利用它编程的概念就叫作“多线程处理(Multithreading)”
settimeout、setinterval函数!!
好像就可以实现的样子,它可以间断性执行啊!
但是,但是,好像不太对,我就搜索了一些浏览器的资料
异步?同步?阻塞?非阻塞?线程?进程?你知道是什么吗?
例如普通B/S模式(同步):提交请求->等待服务器处理->处理完毕返回 这里的是指你提交了一个请求,并没有立即返回,
要等到服务器处理完成后, *连带着返回值一起返回了*
例如 ajax请求(异步): 请求通过事件触发->服务器处理->处理完毕。 这个过程是你触发了事件后,服务端立即返回,
*但是是不带返回值的*, 然后当服务端处理完这件事情后, 通过回掉, promise 等各种方式通知你这个返回值。
通俗一点的例子:
同步:你去楼下拿快递,然后快递小哥说我帮你找找, 在这过程中你一直等着,直到他找到你的快递连同快递一起返回。
异步:你去楼下拿快递,快递小哥说我帮你找,找到打电话通知你, 你该干嘛干嘛去。
阻塞和非阻塞
可以这么理解 阻塞就是当你拿快递的时候, 进程挂起了,你什么也干不了,只能等着快递小哥告诉你答案你才能去做你的事情.
*非阻塞是指,你的read操作立即返回了,但是没有带数据. 可以通过 轮询 来实现非阻塞I/O的获取完完整数据的要求,但是对于应用程序来说,他任是一种同步,
因为程序任然需要等IO完全返回,等待的时间,cpu要么用于遍历文件描述符的状态,要么用于休眠等待事件发生.*
讲到这里我们知道js 是单线程的.js的主要用途是与用户交互,以及操作DOM.
*JavaScript的单线程,与它的用途有关。作为浏览器脚本语言,JavaScript的主要用途是与用户互动,以及操作DOM。这决定了它只能是单线程,否则会带来很复杂的同步问题。比如,假定JavaScript同时有两个线程,一个线程在某个DOM节点上添加内容,另一个线程删除了这个节点,这时浏览器应该以哪个线程为准?*(摘自阮老师的博客)
单线程意味着同一时间只能进行一件事情,前面的事情结束才能执行后面的事件.当碰到需要时间的IO事件的时候问题就来了,必须等到这些结束后才往下进行,但这时CPU是闲着的.这样浪费了很多计算机的性能.
JavaScript语言的设计者意识到,这时主线程完全可以不管IO设备,挂起处于等待中的任务,先运行排在后面的任务。等到IO设备返回了结果,再回过头,把挂起的任务继续执行下去.
***于是,所有任务可以分成两种,一种是同步任务(synchronous),另一种是异步任务(asynchronous)。同步任务指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务;异步任务指的是,不进入主线程、而进入"任务队列"(task queue)的任务,只有"任务队列"通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行。***
(1)所有同步任务都在主线程上执行,形成一个执行栈(execution context stack)。
(2)主线程之外,还存在一个"任务队列"(task queue)。只要异步任务有了运行结果,就在"任务队列"之中放置一个事件。
(3)一旦"执行栈"中的所有同步任务执行完毕,系统就会读取"任务队列",看看里面有哪些事件。那些对应的异步任务,于是结束等待状态,进入执行栈,开始执行。
(4)主线程不断重复上面的第三步。
基础很关键 ,你知道浏览器是什么组成的 吗?
简单来说,浏览器组成可分两部分:Shell+内核。
shell就是指浏览器外壳,就是我们用肉眼能看到的部分,如菜单、工具栏等用户界面。内核,我们就看不到了,他是幕后英雄,我们上网看到的所有东西都先需要经过它处理,然后再把内容呈现到我们眼前。
浏览器内核又可以分成两部分:渲染引擎(layoutengineer或者RenderingEngine)和JS引擎。它负责取得网页的内容(HTML、XML、图像等等)、整理讯息(例如加入CSS等),以及计算网页的显示方式,然后会输出至 显示器或打印机。浏览器的内核的不同对于网页的语法解释会有不同,所以渲染的效果也不相同。所有网页浏览器、电子邮件客户端以及其它需要编辑、显示网络内容的应用程序都需要内核。JS引擎则是解析Javascript语言,执行javascript语言来实现网页的动态效果。最开始渲染引 擎和JS引擎并没有区分的很明确,后来JS引擎越来越独立,内核就倾向于只指渲染引擎。
“内核”只是一个通俗的说法,其英文名称为“Layout engine”,翻译过来就是“排版引擎”,也被称为“页面渲染引擎”(下文中各种说法通用)。它负责取得网页的内容(HTML、XML、图像等等)、整理信息(例如加入CSS等),以及计算网页的显示方式,然后会输出至显示器或打印机。所有网页浏览器、电子邮件客户端以及其它需要编辑、显示网络内容的应用程序都需要排版引擎。
而浏览器的Shell(“外壳)便很好理解了,它是一个面向用户的界面,也就是网页浏览器为我们实现的各种功能。
浏览器不是单线程的
虽然JS运行在浏览器中,是单线程的,每个window一个JS线程,但浏览器不是单线程的,例如Webkit或是Gecko引擎,都可能有如下线程:
- javascript引擎线程
- 界面渲染线程
- 浏览器事件触发线程
- Http请求线程
http://blog.csdn.net/nx8823520/article/details/7513098
http://www.cnblogs.com/Mainz/p/3552717.html
http://www.cnblogs.com/yasmi/articles/5064588.html
查阅了这么多资料,我自己理解的情况如下:
1.js单线程,浏览器多线程
2.浏览器是事件驱动的,浏览器中很多行为是异步的,会创建事件并放入任务队列中
3.浏览器有一个内部大消息循环,Event Loop(事件循环),会轮询大的事件队列并处理事件
4.Ajax请求是异步的,这请求是由浏览器新开一个线程请求,事件回调的时候是放入Event loop单线程事件队列等候处理。
然后就是我的课设代码啦~~
<html>
<head><title>canvas</title>
<meta charset="utf-8">
<link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<style type="text/css">
#show{
width: 1200px;
margin: 0 auto;
}
h3{
text-align: center;
background-color: #FFCC66;
}
</style>
<script type="text/javascript">
var ctx; //绘制图形
var door;
var stop=1;
var A;
var B;
var s;
var l=0;
var everything=[];
var waittime=1000;
var speed=5;
var distance=80;
var lus=[80,420,920,1220];
var passenger=[];
var tid;
var i=0;//station
var text=[];
var station=["S站:","A站:","B站:","终点站:"];
function Bus(bx,sy,style1,style2,style3){
this.bx=bx;
this.sy=sy;
this.fillstyle1=style1;
this.fillstyle2=style2;
this.fillstyle3=style3;
this.movebus=movebus;
this.draw=drawbus;
}
function movebus(){
this.bx+=speed;
distance=this.bx;
}
function drawbus(){
ctx.beginPath();
ctx.fillStyle =this.fillstyle2;
//draw the tyre
ctx.arc(this.bx-40,this.sy+20,10,0,Math.PI*2,true);
ctx.arc(this.bx+20,this.sy+20,10,0,Math.PI*2,true);
ctx.fill();
//draw the bus head
ctx.beginPath();
ctx.fillStyle=this.fillstyle1;
ctx.arc(this.bx+20,this.sy+20,40,0,1.5*Math.PI,true);
ctx.closePath();
ctx.fill();
//draw the bus tri frame
ctx.beginPath();
ctx.fillStyle=this.fillstyle1;
ctx.moveTo(this.bx+20,this.sy+20);
ctx.lineTo(this.bx+60,this.sy+20);
ctx.lineTo(this.bx+20,this.sy-20);
ctx.lineTo(this.bx+20,this.sy+20);
ctx.fill();
//draw the bus footer
ctx.beginPath();
ctx.fillRect(this.bx-60,this.sy-20,80,40);
ctx.closePath();
//draw the door
ctx.beginPath();
if(stop==1){ //stop the bus
ctx.fillStyle="#FF6666";
}else{
ctx.fillStyle="#FFFF66";
}
ctx.fillRect(this.bx-14,this.sy-5,20,25);
}
var bus=new Bus(80,320,"#66CCFF","#800000","#CCCCCC");
function Myway(wx,wy,wwidth,wheight,wtylestring){
this.wx=wx;
this.wy=wy;
this.wwidth=wwidth;
this.wheight=wheight;
this.fillstyle=wtylestring;
this.draw=drawway;
}
function drawway(){
ctx.fillStyle=this.fillstyle;
ctx.fillRect(this.wx,this.wy,this.wwidth,this.wheight);
}
function Line(bx,by,sx,sy,stylestring){
this.bx=bx;
this.by=by;
this.sx=sx;
this.sy=sy;
this.strokeStyle="#804000";
this.draw=drawline;
}
function drawline(){
//draw the bus statino line
var jian=0;//没到站
if(this.bx>=bus.bx-60&&this.bx<=bus.bx+60)
{this.by=this.by-51;jian=1;}
ctx.strokeStyle="#800000";
ctx.lineWidth=10;
ctx.beginPath();
ctx.moveTo(this.bx,this.by);
ctx.lineTo(this.sx,this.sy);
ctx.stroke();
if(jian==1){
this.by+=51;
}
}
function Text(text,font,bx,by){
this.text=text;//文字部分
this.font=font;//字体大小等信息
this.bx=bx;//x坐标
this.by=by;//y坐标
this.draw=drawtext;//开始绘画吧
}
function drawtext(){
//draw the text
ctx.font=this.font;
ctx.fillStyle="#7F7F7F";
ctx.fillText(this.text,this.bx,this.by);
}
var texts=new Text(station[0],"bold 18pt sans-serif",32,190);
var texta=new Text(station[1],"bold 18pt sans-serif",372,190);
var textb=new Text(station[2],"bold 18pt sans-serif",872,190);
var textl=new Text(station[3],"bold 18pt sans-serif",1172,190);
var textdriver=new Text(" ","bold 18pt sans-serif",500,50);
var saleman=new Text(" ","bold 18pt sans-serif",500,80);
text.push(texts);
text.push(texta);
text.push(textb);
text.push(textl);
var ls=new Line(80,340,80,200);
var la=new Line(420,340,420,200);
var lb=new Line(920,340,920,200);
var ll=new Line(1220,340,1220,200);
//站牌绘制
var way=new Myway(20,350,1300,20,"rgb(40,25,10)");
var Sstop=new Myway(25,160,120,40,"#FFCC66");
var Astop=new Myway(365,160,120,40,"#FFCC66");
var Bstop=new Myway(865,160,120,40,"#FFCC66");
var Lstop=new Myway(1165,160,120,40,"#FFCC66");
//移除
everything.push(ls);
everything.push(la);
everything.push(lb);
everything.push(ll);
everything.push(way);
everything.push(Sstop);
everything.push(Astop);
everything.push(Bstop);
everything.push(Lstop);
everything.push(bus);
everything.push(texts);
everything.push(texta);
everything.push(textb);
everything.push(textl);
everything.push(textdriver);
everything.push(saleman);
function init(){
textdriver.text="始发站";
ctx=document.getElementById("canvas").getContext('2d');
drawall();
}
function drawall(){
ctx.clearRect(0,0,1350,400);
var i;
for (i=0;i<everything.length;i++) {
everything[i].draw();
}
}
function start(){
door=0;//open the door
stop=1;//bus is stop
s=Number(document.f.s.value);// the number of station s
A=Number(document.f.a.value);
B=Number(document.f.b.value);
texts.text=station[0]+s+"人";
texta.text=station[1]+A+"人";
textb.text=station[2]+B+"人";
textl.text=station[3];
passenger.push(s);
passenger.push(A);
passenger.push(B);
passenger.push(l);
drawall();
tid=setInterval(go,50);
return false;
}
function go(){
if(distance>=1220){
clearInterval(tid);
saleman.text="";
drawall();
}
drawall();
driver();
drawall();
seller();
drawall();
}
var startTime ;
function seller(){
if(stop==1){
saleman.text="";
if(door==1){
door=0;//open the door
startTime= new Date().getTime();
//暂停0.5s
while (new Date().getTime() < startTime + 500);
}else{
if(passenger[i]>0){
startTime= new Date().getTime();
while (new Date().getTime() < startTime + 500);
passenger[i]-=1;
text[i].text=station[i]+passenger[i]+"人";
}else{
startTime= new Date().getTime();
while (new Date().getTime() < startTime + 500);
door=1;//close the door
i+=1;//station++
}
}
}else{
//when the bus is driving ,show the text
saleman.text="售票员正在售票……";
}
}
function driver(){
if(distance>=lus[i]){
if(stop==0){
stop=1;
}
textdriver.text=station[i];
}else{
if(door==1){
stop=0;
bus.movebus();
textdriver.text="司机正在开车,下一站:"+station[i];
}
}
}
</script>
</head>
<body onLoad="init();">
<h3 >司机与售票员(信号量操作)动画</h3>
<!-- 创建canvas画布 -->
<canvas id="canvas" width="1350" height="400">
your browser doesn't support the HTML5 element canvas.
</canvas><br/>
<div class="panel panel-warning" id="show">
<div class="panel-heading">输入各站的候车人数</div>
<form name="f" id="f" onSubmit="return start();" class="form-horizontal">
<div class="panel-body">
<div class="col-xs-4">
s站<input class="form-control " type="text" name="s" id="s" placeholder="s站候车人数">
</div>
<div class="col-xs-4">
A站<input class="form-control " type="text" name="a" id="a" placeholder="A站候车人数">
</div>
<div class="col-xs-4">
B站<input class="form-control " type="text" name="b" id="b" placeholder="B站候车人数">
</div>
</div>
<div class="panel-footer">
<input type="submit" name="">
</div>
</form>
</div>
<script src="http://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
<script src="http://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"></script>
</body>
</html>