多线程 异步非阻塞进程 阻塞 非阻塞 同步异步 内存管理 需要看哪些书

博客访问: 4922833
博文数量: 724
博客积分: 2150
博客等级: 上尉
技术积分: 12529
注册时间:
IT168企业级官微
微信号:IT168qiye
系统架构师大会
微信号:SACC2013
分类: LINUX
一、同步与异步
同步/异步, 它们是消息的通知机制
1. 概念解释
所谓同步,就是在发出一个功能调用时,在没有得到结果之前,该调用就不返回。
按照这个定义,其实绝大多数函数都是同步调用(例如sin isdigit等)。
但是一般而言,我们在说同步、异步的时候,特指那些需要其他部件协作或者需要一定时间完成的任务。
最常见的例子就是 SendMessage。
该函数发送一个消息给某个窗口,在对方处理完消息之前,这个函数不返回。
当对方处理完毕以后,该函数才把消息处理函数所返回的值返回给调用者。
异步的概念和同步相对。
当一个异步过程调用发出后,调用者不会立刻得到结果。
实际处理这个调用的部件是在调用发出后,
通过状态、通知来通知调用者,或通过回调函数处理这个调用。
以 Socket为例,
当一个客户端通过调用 Connect函数发出一个连接请求后,调用者线程不用等待结果,可立刻继续向下运行。
当连接真正建立起来以后,socket底层会发送一个消息通知该对象。
C. 三种返回结果途径&
执行部件和调用者可以通过三种途径返回结果:
a. & 状态、
b. & 通知、
c. & 回调函数。
可以使用哪一种依赖于执行部件的实现,除非执行部件提供多种选择,否则不受调用者控制。
a. 如果执行部件用状态来通知,
& & 那么调用者就需要每隔一定时间检查一次,效率就很低
& & 有些初学多线程编程的人,总喜欢用一个循环去检查某个变量的值,这其实是一种很严重的错误。
b.&如果是使用通知的方式,
& & 效率则很高,因为执行部件几乎不需要做额外的操作。
c. 至于回调函数,
& & 和通知没太多区别。
2. 举例说明
理解这两个概念,可以用去银行办理业务(可以取钱,也可以存钱)来比喻:
当到银行后,
.可以去ATM机前排队等候 & & & & & & & & & & & & & & & &-- (排队等候)就是同步等待消息
.可以去大厅拿号,等到排到我的号时,
&柜台的人会通知我轮到我去办理业务. & & & & & & &-- (等待别人通知)就是异步等待消息.
在异步消息通知机制中,
等待消息者(在这个例子中就是等待办理业务的人)往往注册一个回调机制,
在所等待的事件被触发时由触发机制(在这里是柜台的人)通过某种机制(在这里是写在小纸条上的号码)
找到等待该事件的人.
在select/poll 等IO 多路复用机制中就是fd,
当消息被触发时,触发机制通过fd 找到处理该fd的处理函数.
3. 在实际的程序中,
同步消息通知机制:就好比简单的read/write 操作,它们需要等待这两个操作成功才能返回;
& & & & & & & & & 同步, 是由处理消息者自己去等待消息是否被触发;
异步消息通知机制:类似于select/poll 之类的多路复用IO 操作,
& & & & & & & & & 当所关注的消息被触发时,由消息触发机制通知触发对消息的处理.
& & & & & & & & & 异步, 由触发机制来通知处理消息者;
还是回到上面的例子,
轮到你办理业务, 这个就是你关注的消息,
而办理什么业务, 就是对这个消息的处理,
两者是有区别的.
而在真实的IO 操作时: 所关注的消息就是 & & 该fd是否可读写,
& & & & & & & & & & &而对消息的处理是 & & 对这个fd 进行读写.
同步/异步仅仅关注的是如何通知消息,它们对如何处理消息并不关心,
好比说,银行的人仅仅通知你轮到你办理业务了,
而办理业务什么业务(存钱还是取钱)他们是不知道的.
二、阻塞与非阻塞
阻塞/非阻塞, 它们是程序在等待消息(无所谓同步或者异步)时的状态.
1. 概念解释
阻塞调用是指调用结果返回之前,当前线程会被挂起。函数只有在得到结果之后才会返回。
有人也许会把阻塞调用和同步调用等同起来,实际上他是不同的。
对于同步调用来说,很多时候当前线程还是激活的,只是从逻辑上当前函数没有返回而已。
socket接收数据函数recv是一个阻塞调用的例子。
当socket工作在阻塞模式的时候, 如果没有数据的情况下调用该函数,则当前线程就会被挂起,直到有数据为止。
非阻塞和阻塞的概念相对应,指在不能立刻得到结果之前,该函数不会阻塞当前线程,而会立刻返回。
C. 对象的阻塞模式和阻塞函数调用
对象是否处于阻塞模式和函数是不是阻塞调用有很强的相关性,但是并不是一一对应的。
阻塞对象上可以有非阻塞的调用方式,我们可以通过一定的API去轮询状态,
在适当的时候调用阻塞函数,就可以避免阻塞。
而对于非阻塞对象,调用特殊的函数也可以进入阻塞调用。函数select就是这样的一个例子。
2. 举例说明
继续上面的那个例子,
不论是排队等待,还是使用号码等待通知,
如果在这个等待的过程中,
. 等待者除了等待消息之外不能做其它的事情,那么该机制就是阻塞的,
& 表现在程序中,也就是该程序一直阻塞在该函数调用处不能继续往下执行.
. 相反,有的人喜欢在银行办理这些业务的时候一边打打电话发发短信一边等待,这样的状态就是非阻塞的,
& 因为他(等待者)没有阻塞在这个消息通知上,而是一边做自己的事情一边等待.
三、易混淆的点
很多人也会把异步和非阻塞混淆,
因为异步操作一般都不会在真正的IO 操作处被阻塞,
比如如果用select 函数,当select 返回可读时再去read 一般都不会被阻塞
就好比当你的号码排到时一般都是在你之前已经没有人了,所以你再去柜台办理业务就不会被阻塞.
可见,同步/异步与阻塞/非阻塞是两组不同的概念,它们可以共存组合,
而很多人之所以把同步和阻塞混淆,我想也是因为没有区分这两个概念,
比如阻塞的read/write 操作中,其实是把消息通知和处理消息结合在了一起,
在这里所关注的消息就是fd 是否可读/写,而处理消息则是对fd 读/写.
当我们将这个fd 设置为非阻塞的时候,read/write 操作就不会在等待消息通知这里阻塞,
如果fd 不可读/写则操作立即返回.
四、同步/异步与阻塞/非阻塞的组合分析
_______阻塞____________________非阻塞_____
同步 | 同步阻塞 & & & & & & &同步非阻塞
异步 | 异步阻塞 & & & & & & &异步非阻塞
同步阻塞形式:
& 效率是最低的,
& 拿上面的例子来说,就是你专心排队,什么别的事都不做。
& 实际程序中
& 就是未对fd 设置O_NONBLOCK 标志位的read/write 操作,
异步阻塞形式:
& 如果在银行等待办理业务的人采用的是异步的方式去等待消息被触发,也就是领了一张小纸条,
& 假如在这段时间里他不能离开银行做其它的事情,那么很显然,这个人被阻塞在了这个等待的操作上面;
& 异步操作是可以被阻塞住的,只不过它不是在处理消息时阻塞,而是在等待消息被触发时被阻塞.
& 比如select 函数,
& 假如传入的最后一个timeout 参数为NULL,那么如果所关注的事件没有一个被触发,
& 程序就会一直阻塞在这个select 调用处.
同步非阻塞形式:
& 实际上是效率低下的,
& 想象一下你一边打着电话一边还需要抬头看到底队伍排到你了没有,
& 如果把打电话和观察排队的位置看成是程序的两个操作的话,
& 这个程序需要在这两种不同的行为之间来回的切换,效率可想而知是低下的;
& 很多人会写阻塞的read/write 操作,
& 但是别忘了可以对fd 设置O_NONBLOCK 标志位,这样就可以将同步操作变成非阻塞的了;
异步非阻塞形式:
& 效率更高,
& 因为打电话是你(等待者)的事情,而通知你则是柜台(消息触发机制)的事情,
& 程序没有在两种不同的操作中来回切换.
& 比如说,这个人突然发觉自己烟瘾犯了,需要出去抽根烟,
& 于是他告诉大堂经理说,排到我这个号码的时候麻烦到外面通知我一下(注册一个回调函数),
& 那么他就没有被阻塞在这个等待的操作上面,自然这个就是异步+非阻塞的方式了.
& 如果使用异步非阻塞的情况,
& 比如aio_*组的操作,当发起一个aio_read 操作时,函数会马上返回不会被阻塞,
& 当所关注的事件被触发时会调用之前注册的回调函数进行处理,
九二,见龙在田,利见大人。
【白话】九二,龙已出现在地上,利于出现德高势隆的大人物。
《象》曰:“见龙在田”,德施普也。
【白话】《象辞》说:“龙已出现在地上”,犹如阳光普照,天下人普遍得到恩惠。
阅读(54732) | 评论(5) | 转发(16) |
相关热门文章
给主人留下些什么吧!~~
看了你的文章后,感觉这里面的概念还是有些自相矛盾的地方,我凭我的理解梳理了一下:/albert1017/p/3914149.html,欢迎指正
connnect操作实际上是可以工作在同步/异步,阻塞/非阻塞的四种组合中的一种,你理解的应该是同步阻塞模式,实际上另三种都是不用等内核层返回结果给用户层后,程序才能继续向下运行。这篇文章讲了这四种组合:http://blog.chinaunix.net/uid--id-3754543.html另外我对socket中应用这四种组合做了专门的示例详解,有兴趣也可以一并看看。
“当一个客户端通过调用&Connect函数发出一个连接请求后,调用者线程不用等待结果,可立刻继续向下运行。”我的理解connect会进行三次握手,首先发SYN包给服务器,客户端socket进入SYN_SEND状态,等待服务端的ACK,如果收到ACK,立刻进入ESTABLISHED状态,两端可以通信了。如果这个过程出现错误,则错误都会以返回值的形式返回调用者。我这里不太明白你说的“调用者不用等待结果,直接向下执行”是什么意思??大侠能否解释下
请登录后评论。首先我简单介绍一下同步TCP编程 与异步TCP编程。
在服务端我们通常用一个TcpListener来监听一个IP和端口。客户端来一个请求的连接,在服务端可以用同步的方式来接收,也可以用异步的方式去接收。比如:
TcpListene server = new TcpListener(IPAddress.Parse(&127.0.0.1&), port);
TcpClient tc =server.AcceptTcpClient();
这里就一个同步接收的方式,那为什么说同步呢,因为在这个端口下如果同是来了两个客户端请求,第一个连接得到响应,与服务端建立通讯,而第二个请求就会被一直阻塞直到第一个请求完成操作,各个请求之间就好像排个队,顺序执行,这就是同步。
异步呢,就是同时来两个或者多个请求,服务端就同时响应多个客户端,同时给他们连接。各个客户端与服务器的通讯是并行的,一个客户端不必等另一个客户端完成操作。通常用这两个方法来接收一个客户端请求。
BeginAcceptTcpClient()
EndAcceptTcpClient()
//----------------------------------------------------------------------------------------------------------------------
最近练习一个程序 订票客户管理系统。用到TCP编程。
这个程序可以从用三种模式来完成。
1.阻塞模式(仅适合短连接)
TcpListene server = new TcpListener(IPAddress.Parse(&127.0.0.1&), port);
while(true)
&&&&&&&&&&&&&& TcpClient tc =server.AcceptTcpClient();
&&&&&&&&&&&&& //& do ........................
来一个连接服务端端就响应了,然执行操作,如果操作没完成再来一个客户端请求就阻塞你,直到第一个请求完成操作。
总结特点:这种模式简单易行,适合客户端请求次数比较少场景。比如一下来了1000个请求,第一个去执行了 ,剩下的999个被阻塞。
2.多线程+阻塞模式(用于长连接和短连接)
TcpListene server = new TcpListener(IPAddress.Parse(&127.0.0.1&), port);
while(true)
&&&&&&&&&&&&&& TcpClient tc =server.AcceptTcpClient();
&&&&&&&&&&&&&&& //接收到客户端请求之后 就起一个线程 负责这个客户端TCP与服务端的通讯
&&&&&&&&&&&&&& Thread& Th=new& Thread(F);
&&&&&&&&&&&&&&& Th.start();//有参数加参数没参数不加
void& F( object& oo)
&&&&&&&&&& //和客户端进行通讯
想 这样,一个请求来个,服务端响应然后给你一个线程负责和你的通讯。然后服务端又去响应其他客户端的请求。而不必等待前一个连接是否完成操作。这样模式由于 引入了多线程,就变成了异步操作就要考虑对临界资源的互斥问题,就是让多个线程访问一个资源时候,去同步他们的操作。这里不再说了。
在负责给客户端的方法中 这里我随便写了个F(object oo)如果关闭当前连接。就是异步的端连接, 如果不关就是异步的长连接。根据需要来确定。
总结特点:这种模式由于引入了多线程,提高了系统的效率,但是要考虑临界资源的互斥问题,如何管理线程生命周期。
3 非阻塞模式
就不在用AcceptTcpClient()这种阻塞方式来接收请求。就是来一个请求马上接收。
通常用这两个方法组合使用
TcpListene server = new TcpListener(IPAddress.Parse(&127.0.0.1&), port);
&server.Start();
&server.BeginAcceptTcpClient(new AsyncCallback(AcceptClient), server);
&& void AcceptClient(IAsyncResult ar)
&&&&&&&&&&& TcpListener server = (TcpListener)ar.AsyncS
&&&&&&&&&&& TcpClient client = server.EndAcceptTcpClient(ar);
当执行BeginAcceptTcpClient时候编译器就会在线程池中创建一个线程监听连接请求,如果有请求就会自动调用委托的方法(这里的AcceptClient)来完成一个 TcpClient 的实例,再来一个客户端请求,线程池又新建一个线程去实例一个TcpClient对象,当然了如果想做长连接的多客户端与服务端的通讯时候,每一个TcpClient对象是要保存起来的,这只是异步的接收请求而已。
听说做大型项目异步接收用的很多。
阅读(...) 评论()> 博客详情
摘要: 聊聊同步,异步,阻塞,非阻塞这四个概念,再给出一些代码上的例子。
定义:任务A,任务B
同步:任务A和任务B之间有关联,例如任务B中途要给任务A一个数字,那么任务A或许需要等待任务B生产这个数,任务A需要等待任务B的这个动作叫做同步。
异步:事件A和事件B之间没有关联,是相互独立的,那么相互都不用管对方干了什么。
定义:线程A和线程B,分别在执行任务A和任务B
阻塞:线程A需要等待线程B,于是线程A在等待这个数的步骤上被挂起,不能分到cpu,不能执行,这样被称为阻塞。
非阻塞:线程同样需要线程B给一个数,但是线程A仅仅告知线程B要给这个数,并没有马上就要使用这个数,此时线程A没有被挂起,仍然能分到cpu,仍然能执行,这样被称为非阻塞。
因此这两对概念并没有冲突,而是能两两组合。只是由于组合后的状态使得大家误解了这两组概念。下面给出java代码上的例子,大家就能比较好的分辨了。
同步阻塞:
int&i&=&System.in.read();
当命令终端没有输入时,调用该方法的线程被阻塞,表现出要和终端作同步。
异步非阻塞:
Future&T&&future&=&threadPool.submit(Callable&T&&callable);
future.get();
callable内的任务结果没有马上需要的必要,于是调用的submit()方法马上返回一个实现Future的存根。callable任务对于当前线程是异步的,不需要阻塞当前线程。
但是到最后当前线程需要callable任务的结果,此处就需要同步,get()方法通过阻塞来实现。
同步非阻塞:
concurrentLinkedQueue.offer((T)&t);
该过程一个元素需要入队列,该并发队列为了让当前线程不阻塞(避免线程切换而耗费时间)而又能正确入队,使用CAS算法实现的乐观锁循环尝试入队。offer()方法并没有阻塞当前线程,而又希望同步,于是通过循环来实现,最终实现同步非阻塞。
异步阻塞:
没有例子。设想一下,阻塞是用来实现同步的,这样和同步阻塞有什么区别,那么实现这个还有什么用?
最后,由于仓促,可能上面有误,如果有误,请多指教,谢谢。
References & Thx:http://blog.chinaunix.net/uid--id-3754118.html
人打赏支持
码字总数 15604
是的,同步异步其实应该是用户程序与内核之间的关系。
支付宝支付
微信扫码支付
打赏金额: ¥
已支付成功
打赏金额: ¥

我要回帖

更多关于 线程同步和异步的区别 的文章

 

随机推荐