IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    闲谈异步调用“扁平”化

    边城狂人发表于 2015-09-13 23:42:42
    love 0

    哦,代码……就把它们当成插图吧

    随着 CPU 从单核变多核,软件从注重功能到注重体验,Web 从页面跳转方式到 Web2.0 的无刷新加载(AJAX),程序员越来越多的接触多线程和异步。而 Android 的主线程中不允许操作网络,更是将程序员们推向了异步的深渊。异步深渊产生的主要原因是回调,这在 nodejs 里尤其严重。

    // [node.js]
    
    doFirstThing(function(err, data) {
        doSecondThing(data, function(err, data) {
            doThirdThing(data, function(err, data) {
                // ... fall down
            })
        });
    });

    为了逃离回调的深渊,大家开始想各种办法来把回调扁平化。

    在 JavaScript 中,Promise(指该类方法而非某个库)成为众多解决方案的佼佼者,并成功被 ES6 采纳。

    // [node.js]
    
    doFirstThing()
        .then(doSecondThing)
        .then(doThirdThing)
        // .then(...) - continuous
        .catch(function() {
            // something wrong
        });

    而 C# 则通过 Task 和 ThreadPool 让异步编程变得容易。前面谈论的 C# 并行计算(Parallel 和 ParallelQuery) 就是基于 Task 的。不过使用 Task.ContinueWith() 和 Parallel.ForEach() 的时候,就会觉得:这不就是 Promise 吗?

    // [csharp]
    
    Task.Run(() => {
        // do first thing and return a data
        return "first";
    }).ContinueWith(task => {
        // do second thing and return a data
        return new []{ task.Result, "second" };
    }).ContinueWith(task => {
        // do final thing
        foreach (string s in task.Result) { Console.WriteLine(s); }
    }).Wait();

    之后 C#5.0 又推出 async/await 方案,将异步代码写得像同步代码一样,由编译器来将 async/await 代码封装成异步 Task 方式,而不是由人工处理,这大大降低了写异步程序的门槛。

    // [csharp]
    
    private async static Task Process() {
        string first = await Task.Run(() => "first");
        string[] all = await Task.Run(() => {
            return new [] { first, "second" };
        });
        
        await(Task.Run(() => {
            foreach (string s in all) { Console.WriteLine(s); }
        }));
    }

    JavaScript 程序员们一边在等着 ES7 的 async/await 特性,一边也没闲着,在 ES6 generator/yield 特性基础上开发了个 co 出来,提供了类似于 async/await 特性的异步编程方式。

    // [node.js]
    
    var co = require("co");
    
    co(function*() {
        var first = yield new Promise(function(resolve) {
            setTimeout(function() {
                resolve("first");
            }, 100);
        });
    
        var all = yield new Promise(function(resolve) {
            setTimeout(function() {
                resolve([first, "second"])
            }, 200);
        })
    
        console.log(all);
    });
    
    // [ 'first', 'second' ]

    不过 co 程序写起来又要写 Generator,又要用 yeild,还常常要封装 Promise,代码仍然不够简洁。所以继续期待 ES7 的 async/await 特性。




沪ICP备19023445号-2号
友情链接