Socket调⽤⽅式(同步,异步,阻塞,⾮阻塞)
同步:
我调⽤⼀个功能,该功能没有结束前,我死等结果。
异步:
当⼀个异步过程调⽤发出后,调⽤者不能⽴刻得到结果。该功能在完成后,通过状态、通知和回调来通知调⽤者。
同步和⾮同步关注的是调⽤者是否等待等待调⽤结果。
举个通俗的例⼦:
你打电话问书店⽼板有没有《分布式系统》这本书,如果是同步通信机制,书店⽼板会说,你稍等,”我查⼀下",然后开始查啊查,等查好了(可能是5秒,也可能是⼀天)告诉你结果(返回结果)。
⽽异步通信机制,书店⽼板直接告诉你我查⼀下啊,查好了打电话给你,然后直接挂电话了(不返回结果)。然后查好了,他会主动打电话给你。在这⾥⽼板通过“回电”这种⽅式来回调。
阻塞:
调⽤我(函数),我(函数)没有接收完数据或者没有得到结果之前,我不会返回。
⾮阻塞:
调⽤我(函数),我(函数)⽴即返回通知调⽤者
以最常⽤的send和recv两个函数为例
⽐如你调⽤send函数发送⼀定的Byte,在系统内部send做的⼯作其实只是把数据传输(Copy)到TCP/IP协议栈的输出缓冲区,它执⾏成功并不代表数据已经成功的发送出去了,如果TCP/IP协议栈没有⾜够的可⽤缓冲区来保存你Copy过来的数据的话...这时候就体现出阻塞和⾮阻塞的不同之处了:对于阻塞模式的socket send函数将不返回直到系统缓冲区有⾜够的空间把你要发送的数据Copy过去以后才返回,⽽对于⾮阻塞的socket来说send会⽴即返回WSAEWOULDDBLOCK告诉调⽤者说:"发送操作被阻塞了!!!你想办法处理吧..."
对于recv函数,同样道理,对于阻塞模式的socket来说如果TCP/IP协议栈的接收缓冲区没有通知⼀个结果给它它就⼀直不返回:耗费着系统资源....对于⾮阻塞模式的socket该函数会马上返回,然后告诉你:WSAEWOULDDBLOCK---"现在没有数据,回头再来看看"
阻塞I/O模型:
⾮阻塞I/O模型:
阻塞和⾮阻塞关注的是调⽤者在等待调⽤结果时的状态。
还是上⾯的例⼦,
你打电话问书店⽼板有没有《分布式系统》这本书,你如果是阻塞式调⽤,你会⼀直把⾃⼰“挂起”,直到得到这本书有没有的结果,如果是⾮阻塞式调⽤,你不管⽼板有没有告诉你,你⾃⼰先⼀边去玩了,当然你也要偶尔过⼏分钟check⼀下⽼板有没有返回结果。
同步异步与阻塞⾮阻塞的关系:
在处理 IO 的时候,阻塞和⾮阻塞都是同步 IO。socket接收数据的recv函数,如果没有数据的情况下调⽤该函数,则当前线程就会被挂起,直到有数据为⽌(同步&阻塞);CSocket中调⽤Receive函数,如果缓冲区中没有数据,这个函数就会⼀直等待,直到有数据才返回,⽽此时,当前线程还会继续处理各种各样的消息(同步&⾮阻塞)。
只有使⽤了特殊的 API 才是异步 IO。
recv函数异步调⽤的⽅式:
Javascript语⾔的执⾏环境是"单线程"(single thread)。所谓"单线程",就是指⼀次只能完成⼀件任务。如果有多个任务,就必须排队。解决⽅法:实现异步。
例1:回调函数。A先告诉B去点亮,然后⾃⼰点亮。B的点亮操作并不会阻塞A。
function lightUp(A, callback){
callback();
A.lightUp();
}
function callback(){
B.lightUp();
}
***同步调⽤时这样的***
var temp = false;
while(!temp){
temp = wait(A.lightUp());
}
B.lightUp();
例2:事件监听。
function AlightUp(){
this.do();
}
function BlightUp(){
this.do();
}
<('done',BlightUp);
例3:发布/订阅。
jQuery.subscribe("done", f2);
function f1(){
setTimeout(function () {
// f1的任务代码
jQuery.publish("done");
}, 1000);
}
f2完成执⾏后,也可以取消订阅(unsubscribe)。
jQuery.unsubscribe("done", f2);
这种⽅法的性质与"事件监听"类似,但是明显优于后者。因为我们可以通过查看"消息中⼼",了解存在多少信号、每个信号有多少订阅者,从⽽监控程序的运⾏。
例4:Promises
Promises对象是CommonJS⼯作组提出的⼀种规范,⽬的是为异步编程提供统⼀接⼝。
简单说,它的思想是,每⼀个异步任务返回⼀个Promise对象,该对象有⼀个then⽅法,允许指定回调函数。⽐如,f1的回调函数f2,可以写成:
f1().then(f2);
function f1(){
var dfd = $.Deferred();
setTimeout(function () {
// f1的任务代码
solve();
}, 500);
return dfd.promise;
}
这样写的优点在于,回调函数变成了链式写法,程序的流程可以看得很清楚。
⽐如,指定多个回调函数:f1().then(f2).then(f3);
再⽐如,指定发⽣错误时的回调函数:f1().then(f2).fail(f3);
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论