同步异步和阻塞是个有关联,但有有区别的东西。很多时候会从直觉上认为 : 同步 = 阻塞, 异步 = 非阻塞。

但实际上他们是完全描述的不同的东西:

同步异步是从request –> Receive Result这个过程的不同来讲的。

而阻塞是指在等待Request结果时,线程是否会挂起。

对于一个IO过程,可能是同步异步中的一种,同时也必然是阻塞或非阻塞。他们正交的结果共有4种:

image

 

1. 同步阻塞

request –> block –> return result

即同步调用后,当函数返回时就能得到IO的结果。

举个例子:小明去图书馆查文献(request),管理员让小明稍等,然后去系统帮小明查(阻塞,可能几分钟查到了,可能要1天才能查到),管理员查到后告诉小明(return result)。这管理员告诉小明结果之前,小明得一直等在哪里,啥也干不了,哪怕是一天。

所以这种模式最大的问题时浪费小明时间,等待特别无聊。在程序中就是浪费CPU周期。

这是一个人类最直接的过程,如我们用Internet系列函数发起HTTP请求,在调用HttpSendRequest()后,一般需要等一会才会返回结果,网络有问题时可能会等上20多s,程序在取到结果后继续向下执行,当然也有可能再发起一个另一个的HTTP请求。

优点:

- 最符合人类思维

- 实现最简单

- 没有数据同步问题

 

缺点:

- request返回前无法停止

- 会阻塞调用线程,当调用线程是UI线程时,会导致整个UI卡住,用户可能会以为程序挂掉了。

- 无法实现并发,如小明要查2篇文献,只能先让管理员查第一篇,然后等到结果后,再让管理员查第二篇(假设管理员一次只能查一篇文献)。小明也不能同时告诉2个管理员,因为在告诉第一个管理员的时候,必须等待其查询结果完成,小明才能干其他的。

 

2. 同步非阻塞

request –> polling –> return result
这是一个不容易理解的模式,同步还能非阻塞?还真能:

举个例子 : 如小明去图书馆查文献,管理员让小明稍等,小明觉得等太无聊,就跑出去玩了(非阻塞),玩一会就回来看看管理员有没有查到。

这个过程中小明没有阻塞,在等到结果前还能干其他的事,比如出去打把dota。但同步的老问题还是在,在管理员没查到前,小明还是不能回家,他打一把dota还要回来看看管理员查到没有。

这个模式在解决某些程序在处理一个request时,预处理比较耗CPU,可以在等待IO的时间内,对下一个request进行预处理,这样前一个IO完毕后,就能立即处理下一个request IO。

优点:

- request返回前可以干干别的,充分利用CPU资源

- 可以实现并发了,比如小明要查2篇文献,他可以到找管理员A(线程1)去查第一篇,然后取找管理员B(线程2)查第二篇(当然,如果只有一个管理员,那么并发就没啥意义的),然后玩一会后挨个来问管理员AB有没有查到,当管理员AB都查到后小明就可以回家了。

 

缺点:

- request返回前无法停止,因为轮询也会卡住调用线程

- 实现比较复杂

- 轮询不是个好设计方案,如果轮询不设间隔时间,会导致CPU高,浪费CPU,如果设置时间间隔,会导致request返回的实际比实际完成的时间要长。

 

3. 异步非阻塞

request –> return(no result) ------> notify result

典型的异步模式,发起request后,会立即返回(不阻塞),但此时IO并没有处理完,等IO处理完后,再通过callback的方式通知调用者。

举个例子 : 如小明去图书馆查文献(request),管理员让小明先回去(return,非阻塞),等查到了就打电话告诉小明(callback)。

异步和同步的区别就在于request返回后是否返回了IO结果。

优点:

- request返回前可以停止,如小明回去后觉得这篇文献不要了,可以和管理员说不查了,或者干脆不鸟管理员了。

- 容易实现并发

缺点:

- 线程同步是个复杂的问题。

 

4. 异步阻塞

异步阻塞没有意义。

 

5. 同步一定是单线程的吗?

不一定,如同步非阻塞中,一个同步请求中可以发起多个线程同时处理多个IO,这样可以提高效率

内容来源于网络如有侵权请私信删除
你还没有登录,请先登录注册
  • 还没有人评论,欢迎说说您的想法!

相关课程