昨天会斌生日,我们决定小小庆祝下。
会斌收拾好芹菜之后拿起球去楼下篮球场投篮去了,我一个人继续做饭。不一会儿大鹏带着蛋糕回来了,天也快黑了。
等我做完最后一个菜的时候,忽然意识到会斌还没回来。
这似乎是一种遥远的记忆在回想。很小很小的时候,我也会在自家楼下和一群孩子踢球什么的总是到天黑的什么都看不见,妈妈做好饭会来喊我回家吃饭的。虽然回家吃饭现在多半成了一种戏谑,然而无法否认这种感觉让我觉得我忽然老了许多。
也许是吧,周二去运动了一下,结果全身肌肉疼了三天,现在坐下都有困难。几个月前我们还可以连续打两天羽毛球的。
关掉油烟机,不吃饭,我去看电影吧。也许叫人回家吃饭这种事情还可以抵抗几年。

连续听了两天阿桑,尤其是那首寂寞在唱歌中的一直很安静。MD,中国互联网连续糟蹋了我一篇博文里两个词组的含义。本来挺严肃的事情写出来都不严肃了… Anyway,一直很安静,似乎是一种很甜蜜的怨念,一种缓缓释放的痛苦。也许普通的我们不适应苦胆,但是对于黑巧克力还是可以接受的吧。

你知道Web 2.0是什么吗?如果你只觉得Facebook,Gmail就是Web 2.0那你也太肤浅了些。说Ajax就是Web 2.0还接近一些。
这里不详细探讨Web 2.0是什么,不过我觉得2.0可以认为是两个线程。Ajax核心是异步请求,其实就是前台界面一个线程跑你的代码,然后浏览器在实现XmlHttpRequest的异步版本时不小心开了另一个线程去请求数据。然后这个不小心被人发现并大肆应用,加上互联网带宽增长的,程序变得更肆无忌惮,2.0个线程成就了互联网的新时代——Web 2.0。

进一步想,若是JavaScript干脆支持多线程你说怎么样?Web N.0哈哈。下面这段话告诉你这是不可能的:

You must be “as tall as an NBA player” to hack on threaded systems, and that means most programmers should run away crying. But they don’t. Instead, as with most other sharp tools, the temptation is to show how big one is by picking up the nearest singlethreaded code and jamming it into a multi-threaded embedding, or tempting racecondition fate otherwise. Occasionally the results are infamous, but too often, with only virtual fingers and limbs lost, no one learns.
Threads violate abstractions six ways to Sunday. Mainly by creating race conditions, deadlock hazards, and pessimistic locking overhead. And still they don’t scale up to handle the megacore teraflop future.
So my default answer to questions such as, “When will you add threads to JavaScript?” is: “over your dead body!” —— Brendan Eich

这可不是随便什么人说说的,Brendan Eich那可是Mozilla的CTO,JavaScript的创始人。基本上在可见的将来JavaScript是不打算支持多线程的。

这并不是说多线程这个金钥匙就关闭了,有很多办法可以实现并行的目的。

Concurrent.Thread

Concurrent.Thread实现了一个树,需要并行的函数注册到Concurrent.Thread里,然后由Concurrent.Thread安排到树中,主线程再进行模拟多线程操作。Concurrent.Thread库很大,实际中应该加载时性能不很好。
以下文字引用自InfoQ

让我来介绍一下Concurrent.Thread,它是一个允许JavaScript进行多线程编程的库,应用它可以大大缓解上文提及的在AJAX开发中与异步通信相关的困难。这是一个用JavaScript写成的免费的软件库,使用它的前提是遵守Mozilla Public License和GNU General Public License这两个协议。你可以从他们的网站下载源代码。

马上来下载和使用源码吧!假定你已经将下载的源码保存到一个名为Concurrent.Thread.js的文件夹里,在进行任何操作之前,先运行如下程序,这是一个很简单的功能实现:

[javascript]
Concurrent.Thread.create
(function()
{
var i = 0;
while (1) { document.body.innerHTML += i++ + “
“; }
});
[/javascript]

执行这个程序将会顺序显示从0开始的数字,它们一个接一个出现,你可以滚屏来看它。现在让我们来仔细研究一下代码,他应用while(1)条件制造了一个不会中止的循环,通常情况下,象这样不断使用一个并且是唯一一个线程的JavaScript程序会导致浏览器看起来象冻结了一样,自然也就不会允许你滚屏。那么为什么上面的这段程序允许你这么做呢?关键之处在于while(1)上面的那条Concurrent.Thread.create()语句,这是这个库提供的一个方法,它可以创建一个新线程。被当做参数传入的函数在这个新线程里执行,让我们对程序做如下微调:

[code=’javascript’]
function f (i)
{
while (1) { document.body.innerHTML += i++ + “
“; }
}

Concurrent.Thread.create(f, 0);
Concurrent.Thread.create(f, 100000);
[/code]

在这个程序里有个新函数f()可以重复显示数字,它是在程序段起始定义的,接着以f()为参数调用了两次create()方法,传给create()方法的第二个参数将会不加修改地传给f()。执行这个程序,先会看到一些从0开始的小数,接着是一些从100,000开始的大数,然后又是接着前面小数顺序的数字。你可以观察到程序在交替显示小数和大数,这说明两个线程在同时运行。

让我来展示Concurrent.Thread的另外一个用法。上面的例子调用create()方法来创建新线程。不调用库里的任何APIs也有可能实现这个目的。例如,前面那个例子可以这样写:

[code=’html’]


[/code]

在script 标签内,很简单地用JavaScript写了一个无穷循环。你应该注意到标签内的type属性,那里是一个很陌生的值(text/x-script.multithreaded-js),如果这个属性被放在script标签内,那么Concurrent.Thread就会在一个新的线程内执行标签之间的程序。你应当记住一点,在本例一样,必须将Concurrent.Thread库包含进来。

有了Concurrent.Thread,就有可能自如的将执行环境在线程之间进行切换,即使你的程序很长、连续性很强。我们可以简要地讨论下如何执行这种操作。简言之,需要进行代码转换。粗略地讲,首先要把传递给create()的函数转换成一个字符串,接着改写直至它可以被分批分次执行。然后这些程序可以依照调度程序逐步执行。调度程序负责协调多线程,换句话说,它可以在适当的时候做出调整以便每一个修改后的函数都会得到同等机会运行。 Concurrent.Thread实际上并没有创建新的线程,仅仅是在原本单线程的基础上模拟了一个多线程环境。

虽然转换后的函数看起来是运行在不同的线程内,但是实际上只有一个线程在做这所有的事情。在转换后的函数内执行同步通信仍然会造成浏览器冻结,你也许会认为以前的那些问题根本就没有解决。不过你不必耽心,Concurrent.Thread提供了一个应用JavaScript 的异步通信方式实现的定制通信库,它被设计成当一个线程在等待服务器的响应时允许其它线程运行。这个通信库存于 Concurrent.Thread.Http下。它的用法如下所示:

[code=’html’]


[/code]

get()方法,就像它的名字暗示的那样,可以通过HTTP的GET方法获得指定URL的内容,它将目标URL作为第一个参数,将一个代表HTTP请求头的数组作为可选的第二个参数。get()方法与服务器交互,当得到服务器的响应后就返回一个XMLHttpRequest对象作为返回值。当get()方法返回时,已经收到了服务器响应,所以就没必要再用回调函数接收结果。自然,也不必再耽心当程序等待服务器的响应时浏览器冻结的情况了。另外,还有一个 post()方法可以用来发送数据到服务器:

[code=’html’]


[/code]

post()方法将目的URL作为第一个参数,要发送的内容作为第二个参数。像get()方法那样,你也可以将请求头作为可选的第三个参数。

Simulating

第二种方法是比较简单的模拟方式,也是通过一个线程去模拟多线程并行执行的过程。以下是库的实现:
[code=’javascript’]
//loops through an array in segments
var threadedLoop = function(array) {
var self = this;

//holds the threaded work
var thread = {
work: null,
wait: null,
index: 0,
total: array.length,
finished: false
};

//set the properties for the class
this.collection = array;
this.finish = function() { };
this.action = function() { throw “You must provide the action to do for each element”; };
this.interval = 1;

//set this to public so it can be changed
var chunk = parseInt(thread.total * .005);
this.chunk = (chunk == NaN || chunk == 0) ? thread.total : chunk;

//end the thread interval
thread.clear = function() {
window.clearInterval(thread.work);
window.clearTimeout(thread.wait);
thread.work = null;
thread.wait = null;
};

//checks to run the finish method
thread.end = function() {
if (thread.finished) { return; }
self.finish();
thread.finished = true;
};

//set the function that handles the work
thread.process = function() {
if (thread.index >= thread.total) { return false; }

//thread, do a chunk of the work
if (thread.work) {
var part = Math.min((thread.index + self.chunk), thread.total);
while (thread.index++ < part) { self.action(self.collection[thread.index], thread.index, thread.total); } } else { //no thread, just finish the work while(thread.index++ < thread.total) { self.action(self.collection[thread.index], thread.index, thread.total); } } //check for the end of the thread if (thread.index >= thread.total) {
thread.clear();
thread.end();
}

//return the process took place
return true;

};

//set the working process
self.start = function() {
thread.finished = false;
thread.index = 0;
thread.work = window.setInterval(thread.process, self.interval);
};

//stop threading and finish the work
self.wait = function(timeout) {

//create the waiting function
var complete = function() {
thread.clear();
thread.process();
thread.end();
};

//if there is no time, just run it now
if (!timeout) {
complete();
}
else {
thread.wait = window.setTimeout(complete, timeout);
}
};

};

// Note: this class is not battle-tested, just personal testing on large arrays
[/code]

搞点测试数据:
[code=’javascript’]
var array = [];
for (var i = 0; i < 500000; i++) { array.push("this is some long string"); } [/code] 启动并行执行: [code='javascript'] //create our new class var work = new threadedLoop(array); //create the action to compare each item with work.action = function(item, index, total) { var check = (item == "this is some long string comparison to slow it down"); document.body.innerHTML = "Item " + index + " of " + total; }; //another action to use when our loop is done work.finish = function(thread) { alert("Thread finished!"); }; //and start our 'thread' work.start(); [/code]

GIF Image Hack

这种方法是在国内网站见到的,蛮好玩的。原理就是搞一张gif图片,能动画的,会自动循环的那种。然后利用每次动画结束后的onload事件启动多个函数的执行。

[code=’javascript’]
var img = new Image();
img.src = “images/animation.gif”;
img.onload = function()
{
alert(“如要关闭请按住ESC键不放,并点击关闭按钮”);
}
[/code]

参考资料

  1. InfoQ: JavaScript多线程编程简介
  2. javascript多线程的实现方法
  3. Simulate Threading Using Javascript

今天周六,像所有的周末,依旧很安静。临走的时候大体看了下,在前台登记来加班的实习生不到30人。
看来大家都有自己的生活吧,至少知道周末没事的时候可以去哪里。
我比较喜欢这种气氛,有时间可以把代码整理的规规整整,为人为己都不失一件好事。其实代码风格这种事情确实是一件自上而下的事情,以前在实验室曾经做过初步的尝试,经过规定和要求加上培训,开发小组的代码风格是可以统一规范起来的。当然小团队和微软这样的集团是不一样的,似乎代码高效和整洁并不是微软的文化。
对了,换了IE8,确实比IE7好了一些。
一天能发两篇blog,这种工作压力还是比较惬意的。

google-reader-bug

今天午休翻Google Reader的时候终于看到Google一个Bug。如上图所示。
请无视这个Bug的题目吧,我发现只有这篇文章才能重现这个Bug…
当然这也更可能是IE的问题。不过跨浏览器兼容应该是Google的事情。我的IE版本是8.0.6001.18783。
也有很小的可能是春哥的问题…

Update:
确实还有不少,比如下图。我冤枉春哥了…

google-reader-bug2

作为一个版权公司,微软还是很看重版权的。不难理解,如果微软不去尊重别人的版权,法律原因先不说,别人也不会尊重微软的版权。令人惊奇的是,在微软的计算机上全部使用微软软件和微软技术,你会发现所有的事情都能做,微软竟然有各种方面的软件,难怪是一个软件帝国。似乎在所有的方向的软件公司或者组织来看,微软都是不容小覷的强大竞争对手(除了搜索)。
微软产品大集合导致的问题就是有些软件真的不好用…比如微软拼音输入法,相比Google输入法和搜狗输入法,那简直就是垃圾,甚至不如Mac上的SunPinYin。另一个是IE…真的,这个东西没法说了。
今天比较紧张,在上海的杨光的同事的Push下,项目进展比较快,他们的应用确实能发现我们产品里的bug,再一次印证一个原则,就是不管产品在预先做了多少测试,在真正使用的时候,尤其是show给boss看的时候,总要出错的…
别抵抗了,你没办法的…
真的,别抵抗了…

不写了,对了,我可以升级IE到IE8看看,说不定好些。

下一个天亮
郭静

用起伏的背影
挡住哭泣的心
有些故事不必说给每个人听
许多眼睛看得太浅太近
错过我没被看见那个自己
用简单的言语解开超载的心
有些情绪是该说给懂的人听
你的热泪比我激动怜惜
我发誓要更努力更有勇气
等下一个天亮
去上次牵手赏花那里散步好吗
有些积雪会自己融化
你的肩膀是我豁达的天堂
等下一个天亮
把偷拍我看海的照片送我好吗
我喜欢我飞舞的头发
和飘着雨还是眺望的眼光
时间可以抹去我的棱角
有些坚持却永远抹不掉
请容许我小小的骄傲
因为有你这样的依靠

有个游戏好像是砸土拨鼠,面前两个项目好像处于这种状态,摁下一个去另一个就跳起来,哈哈。
不过今天应该彻底一些了,至少我把一个洞堵住了,一时半会儿应该挖不开,但是另一个因为冷落了一天,土拨鼠正对着我邪恶地笑呢。决心明天整死它…
今天有点整不清研究方向,找海东谈话,然后被他们三个头脑风暴了一把,留给我的空间很广阔,基本是我觉得哪个方面有前途就可以提出来,我们就做那个方面。海东说我肯定有很多想法,这倒是真的,至少我的无线宇宙太阳能电站还没人实现…话说回来以前毕业设计选题的时候留下来很多题目,都挺想做的,最后做了一个最迫切的,另外几个闲着挺可惜的,等我整理一下看微软能不能做掉。