`

同步、异步转化和任务执行

阅读更多

正如动静是相对的概念,有了它们,世界才充满盎然生气;变和不变也是哲学上的对立统一,在代码的世界里也一样;同步异步呢?在这一篇文字里面已经很粗略地提到了同步和异步各自有些什么好处,接下来,我不妨说一些同步和异步互相转化的故事。

 

先来看看这一段代码:

 

setTimeout(function(){
	while(true){
		alert("In");
	}
},0);
while(true){
	alert("Out");
}

 

它的输出应该是怎样的呢?你可以试一试。

不同浏览器下它的表现不同,有的浏览器下一直显示In的弹出框;有的浏览器下一直显示Out的弹出框;还有的浏览器下先显示一个Out,再不断显示In的弹出框。

那是不是可以这样理解:

上面的代码本意是想描述一个页面的JavaScript代码进行类似于并行线程的执行(setTimeout调用的方法,似乎就是一个异步执行的方法,它本意是不阻止主流程的执行的),可是实际运行的结果发现,原来浏览器运行JavaScript,所谓的异步,只是对开发人员和用户的一个欺骗,世界只是看起来这个样子——实际上,在JavaScript的世界里,其实根本就是“单线程”的嘛!

其实,这是无所谓欺骗的,就如同对于单CPU的机器来说,所谓的多进程,其实也只有一个CPU轮流执行队列里的指令。只是这个世界本来就是那么残酷,也许是我们都看错了……

 

 

同步Ajax和异步Ajax

Ajax通常都是异步的,同步的Ajax调用会将浏览器当前页面挂起,拒绝一切用户操作,直至响应到达:

 

var req = new  XMLHttpRequest();
req.open("GET", url, true);  //true表示异步,false表示同步
req.onreadystatechange  =  callback;
req.send();

 

 

JavaScript的一个悲剧

在JavaScript中,没有一个方法可以让主线程休息一段时间(Java中有sleep和wait),也就是说,如果我想在某一个执行逻辑中,休息一会、等待一会,这样的实现都会变得很困难(Jscex就是用来解决这样的问题的)。这似乎是JavaScript的一个天生的重大缺陷。

Jscex带来的最大好处,就在于可以用同步的思维和编码,来解决异步的问题:

 

var moveAsync = eval(Jscex.compile("$async", function(e, startPos, endPos, duration) {
    for (var t = 0; t < duration; t += 50) {
        e.style.left = startPos.x + (endPos.x - startPos.x) * (t / duration);
        e.style.top = startPos.y + (endPos.y - startPos.y) * (t / duration);
        $await(Jscex.Async.sleep(50));
    }
    e.style.left = endPos.x;
    e.style.top = endPos.y;
}));

 

 

Barrier模式

Barrier是一道篱笆,所有的不同异步线程,都先先后后运行完毕以后(都撞到了篱笆上),再汇成一束主流程继续往后走:


JDK的CyclicBarrier类就是用来实现这个模式的(A synchronization aid that allows a set of threads to all wait for each other to reach a common barrier point.):

 

class Solver {
	final int N;
	final float[][] data;
	final CyclicBarrier barrier;

	class Worker implements Runnable {
		int myRow;

		Worker(int row) {
			myRow = row;
		}

		public void run() {
			while (!done()) {
				processRow(myRow); //执行某一行的逻辑

				try {
					barrier.await(); //该行逻辑执行完毕后,告知一下
				} catch (InterruptedException ex) {
					return;
				} catch (BrokenBarrierException ex) {
					return;
				}
			}
		}
	}

	public Solver(float[][] matrix) {
     data = matrix;
     N = matrix.length;
     barrier = new CyclicBarrier(N,
                                 new Runnable() {
                                   public void run() {
                                     mergeRows(...); //在每一行都处理完毕以后,执行一个merge操作
                                   }
                                 });
     for (int i = 0; i < N; ++i)
       new Thread(new Worker(i)).start();

     waitUntilDone();
   }
}

 

而在JavaScript中,也可以实现类似的效果:

var count = 3;
for(var i=0; i<=count; i++){
	setTimeout(function(){
		doXXX(); // 执行任务
		count --; //每个子任务执行完毕后都标记一下
		if(!count)
			doFinalXXX(); //Barrier的汇总任务
	},0);
}

 

如果有了Jscex,实现可以更简洁:

function (taskA, taskB, taskC) {
    $await(Jscex.Async.parallel(taskA, taskB)); //先并行执行任务A、B
    $await(taskC); //在A、B都完成后再执行C
}

 

 

Future和Promise

Future、Promise是用于并发编程的一种同步构造。它们表示一个对象,这个对象用来作为一次计算的结果的代理,而该结果被初始化为未知,因为这个对象产生时计算还没有结束(或还没有开始)。

Java中有Future可以帮助实现:

 

ExecutorService executor = Executors.newSingleThreadExecutor();
Callable<Object> task = new Callable<Object>() {
	public Object call() throws Exception {
		doXXX();
		return result;
	}
};
Future<Object> future = executor.submit(task);
boolean isCancelled = future.isCancelled(); //查询状态,调用cancel方法可以取消任务
boolean isDone = future.isDone(); //查询状态
Object res = future.get(); // 等待至完成

 

JavaScript可以实现成类似这样子:

 

 

Promise.when(promise1, promise2).then(function (data1, data2) {...});

 

具体请参见这里

 

文章系本人原创,转载请注明出处和作者

  • 大小: 45 KB
0
0
分享到:
评论

相关推荐

    同步执行和异步执行学习Demo

    同步执行要等待上一个任务执行完后才执行下一任务,异步执行是同时执行两个任务

    CLR.via.C#.(中文第3版)(自制详细书签)

    · 使用线程池、任务、取消、计时器和异步I/O操作来设计响应性强、稳定性高和伸缩性大的解决方案 · 借助于异常处理来进行状态管理 · 使用CLR寄宿、AppDomain、程序集加载、反射和C#的dynamic类型来构造具有动态...

    CLR.via.C#.(中文第3版)(自制详细书签)Part1

    · 使用线程池、任务、取消、计时器和异步I/O操作来设计响应性强、稳定性高和伸缩性大的解决方案 · 借助于异常处理来进行状态管理 · 使用CLR寄宿、AppDomain、程序集加载、反射和C#的dynamic类型来构造具有动态...

    CLR.via.C#.(中文第3版)(自制详细书签)Part3

    · 使用线程池、任务、取消、计时器和异步I/O操作来设计响应性强、稳定性高和伸缩性大的解决方案 · 借助于异常处理来进行状态管理 · 使用CLR寄宿、AppDomain、程序集加载、反射和C#的dynamic类型来构造具有动态...

    CLR.via.C#.(中文第3版)(自制详细书签)Part2

    · 使用线程池、任务、取消、计时器和异步I/O操作来设计响应性强、稳定性高和伸缩性大的解决方案 · 借助于异常处理来进行状态管理 · 使用CLR寄宿、AppDomain、程序集加载、反射和C#的dynamic类型来构造具有动态...

    windows驱动开发技术详解-part2

    Windows操作系统的基本原理、NT驱动程序与WDM驱动程序的构造、驱动程序中的同步异步处理方法、驱 动程序中即插即用功能、驱动程序的各种调试技巧等。同时,还针对流行的PCI驱动程序、USB驱动程序 、虚拟串口驱动...

    Windows驱动开发技术详解的光盘-part1

    本书共分23章,内容涵盖了Windows操作系统的基本原理、NT驱动程序与WDM驱动程序的构造、驱动程序中的同步异步处理方法、驱动程序中即插即用功能、驱动程序的各种调试技巧等。同时,还针对流行的PCI驱动程序、USB驱动...

    Python Cookbook

    11.9 用线程实现GUI和异步I/O 的结合 417 11.10 在Tkinter中使用IDLE的 Tree部件 421 11.11 在Tkinter Listbox中支持单行多值 423 11.12 在Tkinter部件之间复制Geometry方法和选项 427 11.13 在Tkinter中实现一...

    Spring 2.0 开发参考手册

    2.6.3. 任务规划 2.6.4. 对Java 5(Tiger)的支持 2.7. 移植到Spring 2.0 2.7.1. 一些变化 2.8. 更新的样例应用 2.9. 改进的文档 I. 核心技术 3. 控制反转容器 3.1. 简介 3.2. 容器和bean的基本原理 3.2.1....

    spring chm文档

    2.4.3. 异步的JMS 2.4.4. JDBC 2.5. Web层 2.5.1. Spring MVC的表单标签库 2.5.2. Spring MVC合理的默认值 2.5.3. Portlet 框架 2.6. 其他特性 2.6.1. 动态语言支持 2.6.2. JMX 2.6.3. 任务规划 2.6.4. 对...

    Spring API

    2.4.4. 异步的JMS 2.4.5. JDBC 2.5. Web层 2.5.1. Spring MVC合理的默认值 2.5.2. Portlet 框架 2.5.3. 基于Annotation的控制器 2.5.4. Spring MVC的表单标签库 2.5.5. 对Tiles 2 支持 2.5.6. 对JSF 1.2支持...

    Spring中文帮助文档

    2.4.4. 异步的JMS 2.4.5. JDBC 2.5. Web层 2.5.1. Spring MVC合理的默认值 2.5.2. Portlet 框架 2.5.3. 基于Annotation的控制器 2.5.4. Spring MVC的表单标签库 2.5.5. 对Tiles 2 支持 2.5.6. 对JSF 1.2支持...

    Spring-Reference_zh_CN(Spring中文参考手册)

    2.4.3. 异步的JMS 2.4.4. JDBC 2.5. Web层 2.5.1. Spring MVC的表单标签库 2.5.2. Spring MVC合理的默认值 2.5.3. Portlet 框架 2.6. 其他特性 2.6.1. 动态语言支持 2.6.2. JMX 2.6 .3. 任务规划 2.6.4. 对Java 5...

    C#微软培训资料

    17.4 异步文件操作 .227 17.5 小 结 .234 第十八章 高 级 话 题 .235 18.1 注册表编程 .235 18.2 在 C #代码中调用 C++和 VB 编写的组件 .240 18.3 版 本 控 制 .249 18.4 代 码 优 化 .252 18.5 小 ...

    asp.net知识库

    完整的在.net后台执行javascript脚本集合 ASP.NET 中的正则表达式 常用的匹配正则表达式和实例 经典正则表达式 delegate vs. event 我是谁?[C#] 表达式计算引擎 正式发布表达式计算引擎WfcExp V0.9(附源码) 运算...

    C#编程经验技巧宝典

    4 &lt;br&gt;0008 为程序设置版本和帮助信息 4 &lt;br&gt;0009 设置Windows应用程序启动窗体 5 &lt;br&gt;0010 设置Web应用程序起始页 5 &lt;br&gt;0011 如何设置程序的出错窗口 5 &lt;br&gt;0012 如何进行程序调试 6 ...

Global site tag (gtag.js) - Google Analytics