关于异步编程

2017-09-01 11:37:16 +08:00
 twogoods

nodejs 这类异步为主导的程序里会出现 callback hell,这里我用 Java 写了一段 callback 嵌套的代码来类比 nodejs

这里的三个嵌套是因为后一个依赖前一个的结果,那么这三个操作应该是不能并行的,所以 nodejs 写出了嵌套代码,那么问题是这种情况下异步式的代码不比同步的代码性能好吧?感觉业务上蛮多都是后一个依赖前一个,并行度并不高,引入异步编程会不会收益不大?

client.getConnection(res -> {
            SQLConnection connection = res.result();
            connection.query("SELECT count(1) FROM T_User", res2 -> {
                connection.query("SELECT count(1) FROM T_Book", res3 -> {
                    System.out.println(res2.result().getRows() + "--" + res3.result().getRows());
                });
            });
        });

同步写法

SQLConnection connection=client.getConnection();
data1=connection.query("SELECT count(1) FROM T_User");
data2=connection.query("SELECT count(1) FROM T_Book");
3347 次点击
所在节点    程序员
18 条回复
Xrong
2017-09-01 11:51:39 +08:00
个人愚见:楼主的例子本身就看不出引入异步编程的好处,只是纯粹为了达到同步效果而不得以采用的写法而已。当然你可以用些 async 之类的库,假装看上去是同步的样子。
jarlyyn
2017-09-01 11:53:33 +08:00
楼主需要了解 async 或者 promise

还有 co 库。

还是嫌麻烦不妨看看 go 之类的语言。
keenwon
2017-09-01 11:59:17 +08:00
nodejs 是单线程,异步非阻塞的

也就是说,三个嵌套的异步请求,有依赖关系,不是每有意义的,意义就在于第一个请求还未执行完的时候,线程空闲下来可以接受新的请求,或者继续执行其他同步代码,而不需要阻塞在哪里傻傻的等

至于 callback hell,楼上说的 async/await,co 等都可以解决
seki
2017-09-01 12:01:44 +08:00
前后依赖的本来就不是能并行的。可以并行的是你有多个不互相作用的任务的时候,可以一起执行
twogoods
2017-09-01 12:04:38 +08:00
@keenwon 我是一个 Java 程序员,一直以来都是同步的方式写代码,Java 本身是多线程的 [线程空闲下来可以接受新的请求] 这个在 Java 里根本不是问题,所以我会有疑问,异步编程在 Java 里的适用场景
a7063888
2017-09-01 12:06:16 +08:00
确实不大
twogoods
2017-09-01 12:07:54 +08:00
@keenwon 再多问一句,你们 node 里 callback 嵌套或者说 async/await 这种用的多吗?用的多是不是也说明并行度不高,异步最大的好处体现的不多?
chmlai
2017-09-01 12:10:57 +08:00
你整个系统又不是只有这个三个操作在跑.
twogoods
2017-09-01 12:19:19 +08:00
@chmlai 所以问题是异步场景多吗?我本事接触的项目感觉不多
gzlock
2017-09-01 12:22:52 +08:00
node 都 8 了还 hell 是多闭塞?鼻塞可以治疗,闭塞别人可帮不了你
bazingaterry
2017-09-01 12:23:08 +08:00
@twogoods JS 天生就几乎没有阻塞的操作,网络请求大多都是异步进行的。
keenwon
2017-09-01 12:44:07 +08:00
@twogoods

1、用的多
2、不是。单线程模型,异步的好处是很大的。

在 node 主线程里,异步不代表并行,而是同一时间只做一件事,要么发起异步操作,要么执行异步操作的回调(有单独的线程检查异步是否执行完成,而且异步回调的执行只有等主线程空闲下来才行,所以 setTimeout 1ms 不一定是 1ms 后立刻执行)。并不是同时在做两件事,如果要真正的并行,可以启动子进程或者使用集群。

所以 node,nignx 这样的东西,利用异步可以以极低的资源占用,处理大量的请求,不需要每请求每进程(线程)

不知道我说清楚了没。写多了同步代码,可能一下子确实不太好理解 js 的异步。
SuperMild
2017-09-01 12:56:00 +08:00
网页需要非常强的容错能力,以便任何一步有问题,网页都不会卡住不动,所以 JS 天生异步。而 web server 是短时间内接受大量请求的典型场景,用单线程异步的语言可以轻易地提高效率,所以 node 的作者选择了 JS。可见,不是为了异步而异步,是有原因的。
momocraft
2017-09-01 13:01:56 +08:00
并没有什么因素让异步自带性能好,js 那么多异步最初只是因为一线程的不得已。

在这个比较中影响性能的不是 api 形式,是下面的 io 阻塞等因素。如果你把这份 java 代码写成 cps 变换那个样子,看上去就和异步 API 差不多,但是不要期待运行会变快。
leonlu
2017-09-01 13:07:31 +08:00
LZ,现在你可以在 js 里边这么写了:

let connection= await client.getConnection();
data1=await connection.query("SELECT count(1) FROM T_User");
data2=await connection.query("SELECT count(1) FROM T_Book");

如果 data1 和 data2 没有啥前后依赖,你可以非常容易地做成并发 io:

let connection= await client.getConnection();
let [data1, data2] = await Promise.all([
connection.query("SELECT count(1) FROM T_User"),
connection.query("SELECT count(1) FROM T_Book")
]);

是不是和 Java 一样好写了。。。
aliuwr
2017-09-01 14:35:24 +08:00
异步和并行是两个概念。
autoxbc
2017-09-01 14:53:05 +08:00
异步并不是一种处理问题的技巧或者方法
而是一种对流程的更高层面的抽象

世界模型本质是异步的

描述世界的语言与这个模型越接近
就越精确自然高效
zhicheng
2017-09-01 22:30:54 +08:00
异步是用来解决 IO Bound 类型的应用。无法解决 CPU Bound,甚至会多些一举。

详细可以仔细看下我的文章。
https://www.textarea.com/zhicheng/yong-python-lijie-fuwuqi-moxing-shang-566/
https://www.textarea.com/zhicheng/yong-python-lijie-fuwuqi-moxing-xia-596/

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/387399

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX