关闭

彻底理解:阻塞、非阻塞、同步、异步、Reactor、Proactor

722人阅读 评论(0) 收藏 举报
分类:
我以前是写AS3的,事件和回调无处不在,天生就是异步的,很少需要讨论这些概念。现在写C#,这些概念提的就多了,所以需要彻底搞明白。如果把技术的逻辑抽象出来,跟生活中的逻辑做比较,你会发现技术包含的道理是多么的朴素呀。

本程序中的代码大部分是示意代码,不能真正运行。

1、阻塞:阻塞是指当前线程被堵住了,不能继续往下执行了,就被操作系统挂起了。

阻塞的对象是当前线程,而不是IO被阻塞了;外部资源(通常是IO)使得当前线程被挂起才叫阻塞,内部程序执行的再慢也不叫阻塞,比如一个JPEG.Encode(),虽然这个函数的执行很慢,但它仍然在执行,不叫阻塞。阻塞的核心表现是等待,什么事情都做不了,只有等待。

2、非阻塞:调用外部资源,不管结果如何,不会阻挡线程的继续执行。

3、同步:“调用”然后得到“结果”。可能立即得到结果,可能等待一毫秒,也可能等待一辈子,反正结果必须紧随其后。

同步的概念关键在于结果必须紧随调用者之后到来,可以有等待,也可以没有等待,不管有没有等待,同步跟阻塞都没有必然关系。比如同步非阻塞接口Socket.NoBlockRecv(),一旦调用它,有数据就返回数据,没数据就返回空数据或错误,反正不会让你等待。

还有一个同步非阻塞的例子是协程,协程是一种巧妙的机制,既实现了同步返回结果(不像Socket.NoBlockRecv()没有数据就返回空数据或错误当结果),又不会阻塞当前线程。下面是Unity3D的协程的例子:

   IEnumerator WaitAndDebug()
    {
          //打印一句日志
        Debug.Log("WaitAndDebug start" + Time.time);
        //这句的执行要花费5秒,但5秒时间段内,当前线程可以干其它事,同步非阻塞。
        yield return new WaitForSeconds(5);
        //5秒后再打印一句日志
        Debug.Log("WaitAndDebug done" + Time.time);
    }

4、异步:“调用”,有“结果”再通知我。异步跟同步的区别是,结果返回时间点跟调用发起时间点没有强制关系,调用者是被动得到结果的,不是主动等待结果的。

5、Reactor:响应模式,我是被动的,外部要我干什么,我就干什么,受外部驱动。Reactor模式虽然起源于网络IO设计,但这种思想是通用的。基于Reactor模式的网络IO是这样的:

首先声明要监听哪些事件
socket.addEventHandler("receiveEvent",  receiveHandler);
socket.addEventHandler("canSendEvent",  canSendHandler);

function receiveHandler()
{
     socket.receive();//IO告诉我有数据来了,我才去接收数据,同步的
}

function canSendHandler()
{
     socket.send();//IO告诉我它不繁忙了,可以发送数据了,我才去发数据,同步的
}

Reactor的核心是被动响应,程序响应IO事件,具体的收发操作还是需要程序自己去完成,虽然这期间没有阻塞,但收发操作还是同步的。

6、Proactor:主动模式,我是主动的,我想什么时候干,就什么时候干,不受外部驱动。基于Proactor模式的网络IO是这样的:

socket.addEventHandler("receiveSuccessEvent",  receiveSuccessHandler);
socket.addEventHandler("sendSuccessEvent", sendSuccessHandler);

//不用关心IO是否繁忙,发就是了,成功了会通知我的,通过sendSuccessEvent事件
socket.sendAsync(data);
//不用关心有没有数据,我想何时接收就接收,如果我不执行接收,就永远不会触发receiveSuccessEvent事件
socket.receiveAsync();

function receiveSuccessHandler(data)
{
    log("received data");//IO已经把数据接收好了,然后通知我,异步的
}

function sendSuccessHandler()
{
     log("send data success");//IO把数据发送成功了,然后通知我,异步的
}

举个形象的例子:去银行取款。
Reactor:拿号,某个柜台空闲了就通知我去取款,我还是必须坐到柜台前取款,取款过程还是同步的。
Proactor:拿号,告诉大堂经理我要取款,款到了,大唐经理送到我手中,取款过程是异步的。

以上都是个人理解,如果有错误的地方,欢迎大家指正。



0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:70673次
    • 积分:1071
    • 等级:
    • 排名:千里之外
    • 原创:36篇
    • 转载:8篇
    • 译文:0篇
    • 评论:16条
    文章分类
    最新评论