Gevent学习之阻塞与非阻塞
阻塞和非阻塞
阻塞和非阻塞
阻塞和非阻塞指的是调用者(程序)在等待返回结果(或输入)时的状态。
阻塞时,在调用结果返回前,当前线程会被挂起,并在得到结果之后返回。
非阻塞时,如果不能立刻得到结果,则该调用者不会阻塞当前线程。
因此对应非阻塞的情况,调用者需要定时轮询查看处理状态。
阻塞就是干不完不准回来,
非阻塞就是你先干,我现看看有其他事没有,完了告诉我一声
我们拿最常用的send和recv两个函数来说吧...
比如你调用send函数发送一定的Byte,在系统内部send做的工作其实只是把数据传输(Copy)到TCP/IP协议栈的输出缓冲区,它执行成功并不代表数据已经成功的发送出去了,如果TCP/IP协议栈没有足够的可用缓冲区来保存你Copy过来的数据的话...这时候就体现出阻塞和非阻塞的不同之处了:对于阻塞模式的socket send函数将不返回直到系统缓冲区有足够的空间把你要发送的数据Copy过去以后才返回,而对于非阻塞的socket来说send会立即返回WSAEWOULDDBLOCK告诉调用者说:"发送操作被阻塞了你想办法处理吧..."
对于recv函数,同样道理,该函数的内部工作机制其实是在等待
TCP/IP协议栈的接收缓冲区通知它说:嗨,你的数据来了.对于阻塞模式的socket来说如果TCP/IP协议栈的接收缓冲区没有通知一个结果给它它就一直不返回:耗费着系统资源....对于非阻塞模式的socket该
函数会马上返回,然后告诉你:WSAEWOULDDBLOCK---"现在没有数据,回头在来看看"。
非阻塞connect写法
非阻塞connect写法
非阻塞connect是指在网络编程中,客户端发起连接请求时不
会被阻塞,而是立即返回,可以在后续的代码中通过轮询或者回调
的方式来获取连接是否建立成功。
在实际编程中,可以通过设置套
接字为非阻塞模式来实现非阻塞connect。
在C/C++语言中,可以使用以下步骤来实现非阻塞connect的
写法:
1. 创建套接字,使用socket函数创建套接字。
2. 设置为非阻塞模式,使用fcntl函数或者ioctl函数将套接
字设置为非阻塞模式。
3. 发起连接请求,使用connect函数向服务器发起连接请求。
4. 检测连接状态,在非阻塞模式下,connect函数会立即返回,并不保证连接一定会成功建立。
可以使用select函数、poll函数
或者epoll函数等进行轮询,或者使用回调函数来检测连接状态。
5. 处理连接结果,根据轮询或者回调的结果,可以判断连接是
否成功建立,如果连接成功,则可以进行后续的数据传输操作;如
果连接失败,则可以进行相应的处理,比如重新发起连接请求或者
进行错误处理。
在Python语言中,可以使用socket模块提供的
setblocking(False)方法将套接字设置为非阻塞模式,然后使用connect方法发起连接请求,最后通过select模块进行状态检测。
总之,非阻塞connect的写法需要将套接字设置为非阻塞模式,并通过轮询或者回调来检测连接状态,以实现在发起连接请求时不
被阻塞的效果。
Winsocket入门教程二:非阻塞式服务器和客户端程序(TCP)
Winsocket入门教程二:非阻塞式服务器和客户端程序(TCP) 收藏上次为大家介绍了阻塞式多线程服务端程序和阻塞式客户端程序的设计方法,但是在上文的最后也提到过,服务器程序会因为建立连接和关闭连接而频繁的创建和关闭线程会产生大量的内存碎片,从而导致服务端程序不能保证长时间的稳定运行。
因此我在这里为大家介绍另外一种建立服务器和客户端程序的方法,即建立非阻塞式的服务器和客户端程序。
那什么是非阻塞呢?非阻塞是相对于阻塞而言,阻塞指的是在进行一个操作的时候,如服务器接收客户端的连接(accept),服务器或者客户端读写数据(read、write),如果该操作没有执行完成(成功或者失败都算是执行完成),则程序会一直阻塞在操作执行的地方,直到该操作返回一个明确的结果。
而非阻塞式程序则不一样,非阻塞式程序会在产生阻塞操作的地方阻塞一定的时间(该时间可以由程序员自己设置)。
如果操作没有完成,在到达所设置的时间之后,无论该操作成功与否,都结束该操作而执行程序下面的操作。
为了执行非阻塞操作,我们在创建了一个套接口后,需要将套接口设置为非阻塞的套接口。
为了将套接口设置成为非阻塞套接口,我们需要调用ioctlsocket函数将套接口设置为非阻塞的套接口。
ioctlsocket函数的定义如下:int ioctlsocket( SOCKET s, long cmd, u_long FAR *argp)该函数的作用是控制套接口的I/O模式。
参数s表示要设置的套接口;参数cmd表示要对该套接口设置的命令,为了要将套接口设置成为非阻塞的,我们应该填写FIONBIO;argp表示填写命令的值,如我们要将套接口设置成非阻塞的,我们需要将值设置成为1,如果我们要将套接口设置成为非阻塞状态的话,我们将值设置成为0就是了。
为了进行非阻塞的操作,我们需要在进行操作之前调用select函数,select函数的定义如下:int select(int nfds, fd_set FAR *readfds, fd_set FAR *writefds,fd_set FAR *exceptfds,const struct timeval FAR *timeout);该函数设定一个或多个套接口的状态,并进行必要的等待,以便执行异步I/0(非阻塞)操作。
Verilog中阻塞与非阻塞的区别
下面我们具体分析一下阻塞和非阻塞赋值的语义本质:阻塞:在本语句中“右式计算”和“左式更新”完全完成之后,才开始执行下一条语句;非阻塞:当前语句的执行不会阻塞下一语句的执行。
先看阻塞赋值的情况:我们来看这段代码:always @(posedge Clk)beginQ1 = D;Q2 = Q1;Q3 = Q2;endalways语句块对Clk的上升沿敏感,当发生Clk 0~1的跳变时,执行该always语句。
在begin...end语句块中所有语句是顺序执行的,而且最关键的是,阻塞赋值是在本语句中“右式计算”和“左式更新”完全完成之后,才开始执行下一条语句的。
在本例中,D的值赋给Q1以后,再执行Q2 = Q1;同样在Q2的值更新以后,才执行Q3 = Q2。
这样,最终的计算结果就是Q3 = D。
所有的语句执行完以后,该always语句等待Clk的上升沿,从而再一次触发begin...end语句。
接下来,再看看非阻塞赋值的情况。
所谓非阻塞赋值,顾名思义,就是指当前语句的执行不会阻塞下一语句的执行。
always @(posedge Clk)beginQ1 <= D;Q2 <= Q1;Q3 <= Q2;end首先执行Q1 <= D,产生一个更新事件,将D的当前值赋给Q1,但是这个赋值过程并没有立刻执行,而是在事件队列中处于等待状态。
然后执行Q2 <= Q1,同样产生一个更新事件,将Q1的当前值(注意上一语句中将D值赋给Q1的过程并没有完成,Q1还是旧值)赋给Q2,这个赋值事件也将在事件队列中处于等待状态。
再执行Q3 <= Q2,产生一个更新事件,将Q2的当前值赋给Q3,这个赋值事件也将在事件队列中等待执行。
这时always语句块执行完成,开始对下一个Clk上升沿敏感。
那么什么时候才执行那3个在事件队列中等待的事件呢?只有当当前仿真时间内的所有活跃事件和非活跃事件都执行完成后,才开始执行这些非阻塞赋值的更新事件。
网络编程技术(西电课件)_第8章-1
阻塞与非阻塞通信小结
通信包括阻塞和非阻塞两种模式。在网络编程时, 选择通信模式是一件很重要的事情。对于不同的协 议,阻塞通信和非阻塞通信有不同的表现。 对于UDP协议而言,由于UDP没有发送缓存,因 此所有UDP协议即使在阻塞模式下也不会发生阻 塞。 对于面向连接的协议,在连接建立阶段,阻塞与 非阻塞也表现不一。在阻塞模式下,如果没有连接 请求到达,则等待连接调用将阻塞直到有连接请求 到达;但在非阻塞模式下,如果没有连接请求到达, 等待连接调用将直接返回。
int main(int argc, char* argv[]) { WSADATA wsaData; SOCKET sListen, sClient; SOCKADDR_IN local, client; int iAddrSize = sizeof(SOCKADDR_IN); DWORD dwThreadId; // 初始化Winsock动态链接库 WSAStartup(0x0202, &wsaData); // 创建套接字 sListen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
在连接建立阶段,不管是阻塞模式还是非阻塞 模式,发起连接请求的一方总是会使调用它的进 程阻塞,阻塞间隔最少等于到达服务器的一次往 返时间。 通信模式对应用程序的设计方法也有直接的影 响。在非阻塞模式下,应用程序必须不断地轮询 是否有数据到达或有连接请求到达。 这种轮询的方式耗费的CPU资源较大,要尽可 能避免使用,而在阻塞模式下则不存在这一问题, 但其缺点是进程或线程在执行I/O操作时将被阻 塞而不能执行其他的工作,因此在单进程或单线 程应用中不能使用这种模式。 在多线程应用中比较适合采用阻塞模式,一个 线程被阻塞不影响其他线程的工作。
linux下recvsend阻塞非阻塞区别和用法
linux下recv、send阻塞、非阻塞区别和用法非阻塞IO 和阻塞IO:在网络编程中对于一个网络句柄会遇到阻塞IO 和非阻塞IO 的概念, 这里对于这两种socket 先做一下说明:基本概念:阻塞IO::socket 的阻塞模式意味着必须要做完IO 操作(包括错误)才会返回。
非阻塞IO::非阻塞模式下无论操作是否完成都会立刻返回,需要通过其他方式来判断具体操作是否成功。
(对于connect,accpet操作,通过select判断,对于recv,recvfrom,send,sendto 通过返回值+错误码来判断)IO模式设置:SOCKET对于一个socket 是阻塞模式还是非阻塞模式的处理方法::方法::用fcntl 设置;用F_GETFL获取flags,用F_SETFL设置flags|O_NONBLOCK;同时,recv,send 时使用非阻塞的方式读取和发送消息,即flags设置为MSG_DONTWAIT实现fcntl 函数可以将一个socket 句柄设置成非阻塞模式:flags = fcntl(sockfd, F_GETFL, 0);//获取文件的flags值。
fcntl(sockfd, F_SETFL, flags | O_NONBLOCK); //设置成非阻塞模式;flags = fcntl(sockfd,F_GETFL,0);fcntl(sockfd,F_SETFL,flags&~O_NONBLOCK); //设置成阻塞模式;并在接收和发送数据时:将recv, send 函数的最后有一个flag 参数设置成MSG_DONTWAITrecv(sockfd, buff, buff_size,MSG_DONTWAIT); //非阻塞模式的消息发送send(scokfd, buff, buff_size, MSG_DONTWAIT); //非阻塞模式的消息接受普通文件对于文件的阻塞模式还是非阻塞模式::方法1、open时,使用O_NONBLOCK;方法2、fcntl设置,使用F_SETFL,flags|O_NONBLOCK;消息队列对于消息队列消息的发送与接受:://非阻塞msgsnd(sockfd,msgbuf,msgsize(不包含类型大小),IPC_NOWAIT)//阻塞msgrcv(scokfd,msgbuf,msgsize(**),msgtype,IPC_NOWAIT);读阻塞与非阻塞读的区别: //阻塞和非阻塞的区别在于没有数据到达的时候是否立刻返回.读(read/recv/msgrcv):读的本质来说其实不能是读,在实际中, 具体的接收数据不是由这些调用来进行,是由于系统底层自动完成的。
connectex非阻塞用法
ConnectEx是Windows评台上用于非阻塞式socket通信的函数。
在应用程序中,如果需要进行大量的网络数据读写操作时,通常会选择使用非阻塞式socket,以避免由于网络延迟或其他原因而导致程序阻塞在某个网络I/O操作上,影响程序的整体性能。
ConnectEx函数需要通过调用WS本人octl函数来获取,它的使用方式比较特殊,需要遵循一定的规则才能正确调用。
下面将详细介绍ConnectEx的非阻塞用法。
1. 准备工作在使用ConnectEx函数之前,首先需要创建一个socket,并且设置为非阻塞模式。
这可以通过调用WSASocket函数和ioctlsocket函数来实现。
具体步骤如下:1)调用WSASocket函数创建一个socket,指定协议族、类型和协议参数。
2)调用ioctlsocket函数,将socket设置为非阻塞模式。
2. 获取ConnectEx函数指针在进行ConnectEx函数的调用之前,需要通过调用WS本人octl函数获取ConnectEx函数的指针。
具体步骤如下:1)创建一个用于获取ConnectEx函数指针的GUID变量。
2)调用WS本人octl函数,传入上一步创建的GUID变量,以及其他必要的参数,来获取ConnectEx函数的指针。
3. 调用ConnectEx函数得到ConnectEx函数的指针之后,就可以通过调用它来进行非阻塞式的socket连接操作了。
调用ConnectEx函数需要传入已创建并设置为非阻塞模式的socket,以及目标主机的位置区域信息等参数。
调用步骤如下:1)准备好用于保存连接结果的变量。
2)准备好用于保存连接请求数据的变量。
3)调用ConnectEx函数,传入上述准备好的参数,进行非阻塞式的连接操作。
4. 处理连接结果由于ConnectEx函数是异步的,它的调用结果并不是立即可知的。
在调用ConnectEx函数之后,需要通过轮询或者回调函数等方式来等待连接结果,并做出相应的处理。
Winsocket入门教程二非阻塞式服务器和客户端程序
上次为大伙儿介绍了堵塞式多线程服务端程序和堵塞式客户端程序的设计方法,然而在上文的最后也提到过,服务器程序会因为建立连接和关闭连接而频繁的创建和关闭线程会产生大量的内存碎片,从而导致服务端程序不能保证长时刻的稳固运行。
因此我在那个地点为大伙儿介绍另外一种建立服务器和客户端程序的方法,即建立非堵塞式的服务器和客户端程序。
那什么是非堵塞呢?非堵塞是相关于堵塞而言,堵塞指的是在进行一个操作的时候,如服务器接收客户端的连接(accept),服务器或者客户端读写数据(read、write),假如该操作没有执行完成(成功或者失败都确实是执行完成),则程序会一直堵塞在操作执行的地点,直到该操作返回一个明确的结果。
而非堵塞式程序则不一样,非堵塞式程序会在产生堵塞操作的地点堵塞一定的时刻(该时刻能够由程序员自己设置)。
假如操作没有完成,在到达所设置的时刻之后,不管该操作成功与否,都终止该操作而执行程序下面的操作。
为了执行非堵塞操作,我们在创建了一个套接口后,需要将套接口设置为非堵塞的套接口。
为了将套接口设置成为非堵塞套接口,我们需要调用ioctlsocket函数将套接口设置为非堵塞的套接口。
ioctlsocket函数的定义如下:int ioctlsocket( SOCKET s, long cmd, u_long FAR *argp)该函数的作用是操纵套接口的I/O模式。
参数s表示要设置的套接口;参数cmd表示要对该套接口设置的命令,为了要将套接口设置成为非堵塞的,我们应该填写FIONBIO;argp表示填写命令的值,如我们要将套接口设置成非堵塞的,我们需要将值设置成为1,假如我们要将套接口设置成为非堵塞状态的话,我们将值设置成为0确实是了。
为了进行非堵塞的操作,我们需要在进行操作之前调用select函数,select函数的定义如下:int select(int nfds, fd_set FAR *readfds, fd_set FAR *writefds,fd_set FAR *exceptfds,const struct timeval FAR *timeout);该函数设定一个或多个套接口的状态,并进行必要的等待,以便执行异步I/0(非堵塞)操作。
linux下串口的阻塞和非阻塞操作
linux下串口的阻塞和非阻塞操作linux下串口的阻塞和非阻塞操作[cpp]有两个可以进行控制串口阻塞性(同时控制read和write):一个是在打开串口的时候,open函数是否带O_NDELAY;第二个是可以在打开串口之后通过fcntl()函数进行控制。
阻塞的定义:对于read,block指当串口输入缓冲区没有数据的时候,read函数将会阻塞在这里,移植到串口输入缓冲区中有数据可读取,read读到了需要的字节数之后,返回值为读到的字节数;对于write,block指当串口输出缓冲区满,或剩下的空间小于将要写入的字节数,则write将阻塞,一直到串口输出缓冲区中剩下的空间大于等于将要写入的字节数,执行写入操作,返回写入的字节数。
非阻塞的定义:对于read,no block指当串口输入缓冲区没有数据的时候,read函数立即返回,返回值为0。
对于write,no block指当串口输出缓冲区满,或剩下的空间小于将要写入的字节数,则write将进行写操作,写入当前串口输出缓冲区剩下空间允许的字节数,然后返回写入的字节数。
[cpp]static int set_opt(int fd, int nSpeed, int nBits, char nEvent, int nStop) { struct termios newtio;struct termios oldtio;if(tcgetattr(fd,&oldtio) != 0){ perror("SetupSerial 1"); return -1; }bzero(&newtio,sizeof(newtio)); newtio.c_cflag |= CLOCAL |CREAD; newtio.c_cflag &=~CSIZE; /***********数据位选择****************/ switch(nBits){ case 7: newtio.c_cflag |= CS7; break; case 8: newtio.c_cflag |= CS8; break; }/***********校验位选择****************/switch(nEvent) { case 'O':newtio.c_cflag |= PARENB; newtio.c_cflag |= PARODD; newtio.c_iflag |= (INPCK | ISTRIP); break; case 'E': newtio.c_iflag |= (INPCK |ISTRIP); newtio.c_cflag |= PARENB; newtio.c_cflag &= ~PARODD; break;case 'N': newtio.c_cflag &= ~PARENB; break; } /***********波特率选择****************/ switch(nSpeed){ case 2400:cfsetispeed(&newtio,B2400);cfsetospeed(&newtio,B2400); break; case 4800: cfsetispeed(&newtio,B4800); cfsetospeed(&newtio,B4800); break; case 9600: cfsetispeed(&newtio,B9600); cfsetospeed(&newtio,B9600); break; case 57600: cfsetispeed(&newtio,B57600); cfsetospeed(&newtio,B57600); break; case 115200:cfsetispeed(&newtio,B115200);cfsetospeed(&newtio,B115200); break; case 460800:cfsetispeed(&newtio,B460800);cfsetospeed(&newtio,B460800); break; default: cfsetispeed(&newtio,B9600); cfsetospeed(&newtio,B9600);break; } /***********停止位选择****************/ if(nStop ==1){ newtio.c_cflag &=~CSTOPB; } else if(nStop==2){ newtio.c_cflag |= CSTOPB; } newtio.c_cc[VTIME] = 1; newtio.c_cc[VMIN] = FRAME_MAXSIZE; //阻塞条件下有效tcflush(fd,TCIFLUSH);if((tcsetattr(fd,TCSANOW,&newtio)) != 0){ perror("com set error"); return -1; } printf("set done!\n"); return 0; }[cpp] view plaincopy?static int open_port(int fd,int comport) { /***********打开串口1****************/if(comport == 1) { fd =open("/dev/ttyAT1",O_RDWR|O_NOCTTY|O_NDELAY);if(fd == -1){ perror("Can't Open Serial Port"); return -1; } } /***********打开串口2****************/ else if(comport == 2) { fd =open("/dev/ttyAT2",O_RDWR|O_NOCTTY|O_NDELAY);if(fd == -1){ perror("Can't Open Serial Port"); return-1; } } /***********打开串口3****************/ else if(comport == 3){ fd =open("/dev/ttyAT3",O_RDWR|O_NOCTTY|O_NDELAY);if(fd == -1){ perror("Can't Open Serial Port"); return-1; } } if(comport == 1) { if(fcntl(fd,F_SETFL,FNDELAY) < 0)//非阻塞,覆盖前面open的属性{ printf("fcntl failed\n"); } else{ printf("fcntl=%d\n",fcntl(fd,F_SETFL,FN DELAY)); } } else{ if(fcntl(fd,F_SETFL,0) < 0){ //阻塞,即使前面在open串口设备时设置的是非阻塞的,这里设为阻塞后,以此为准printf("fcntl failed\n"); } else{ printf("fcntl=%d\n",fcntl(fd,F_SETFL,0));} } if(isatty(STDIN_FILENO) == 0){ printf("standard input is not a terminal device\n"); }else{ printf("isattysucess!\n"); } printf("fd-open=%d\n",fd); return fd; }所以,linux的串口的阻塞性通过fcntl()函数进行设置即可。
阻塞线程和非阻塞线程
阻塞线程和非阻塞线程阻塞线程和非阻塞线程是计算机领域中常用的概念,它们与多线程编程密切相关。
本文将详细介绍阻塞线程和非阻塞线程的概念、原理和应用。
一、阻塞线程在多线程编程中,阻塞线程是指当一个线程在执行过程中,因为某种原因无法继续执行,从而暂停线程的执行。
阻塞线程的主要原因包括等待用户输入、等待磁盘IO、等待网络IO等。
当线程被阻塞时,它会进入一个等待状态,直到满足某个条件后才能继续执行。
阻塞线程的特点是在等待某个操作完成期间,线程处于休眠状态,不会占用CPU资源。
这样可以提高系统的资源利用率,但同时也会造成程序的执行效率降低。
因此,在设计多线程程序时需要合理地使用阻塞线程,避免过多的阻塞操作,以提高程序的性能。
二、非阻塞线程与阻塞线程相对应的是非阻塞线程。
非阻塞线程是指在执行过程中,线程不会因为某个操作的阻塞而暂停执行,它会继续执行其他任务,而不是等待该操作的完成。
当一个非阻塞线程需要等待某个操作完成时,它会通过轮询或回调的方式来获知操作的结果,从而继续执行后续的任务。
非阻塞线程的特点是能够充分利用CPU资源,提高程序的执行效率。
但同时,非阻塞线程也会增加系统的负担,因为它需要不断地轮询或回调来获取操作结果,这可能会消耗大量的CPU资源。
因此,在使用非阻塞线程时需要权衡系统的负载和性能要求,选择合适的方式来处理。
1. 阻塞线程的应用:(1) 网络编程:在网络编程中,阻塞线程常用于接收和发送数据,等待网络IO的完成。
(2) 用户交互:在图形界面编程中,阻塞线程常用于等待用户输入,如等待按钮点击、等待输入框输入等。
(3) 文件操作:在文件操作中,阻塞线程常用于等待磁盘IO的完成,如读取文件、写入文件等。
2. 非阻塞线程的应用:(1) 服务器编程:在服务器编程中,非阻塞线程常用于处理并发请求,提高服务器的处理能力。
(2) GUI编程:在图形界面编程中,非阻塞线程常用于更新UI 界面,保持界面的流畅和响应性。
C#阻塞模式和非阻塞模式
C#阻塞模式和⾮阻塞模式阻塞模式 Windows套接字在阻塞和⾮阻塞两种模式下执⾏I/O操作。
在阻塞模式下,在I/O操作完成前,执⾏的操作函数⼀直等候⽽不会⽴即返回,该函数所在的线程会阻塞在这⾥。
相反,在⾮阻塞模式下,套接字函数会⽴即返回,⽽不管I/O是否完成,该函数所在的线程会继续运⾏。
在阻塞模式的套接字上,调⽤任何⼀个Windows Sockets API都会耗费不确定的等待时间。
图所⽰,在调⽤recv()函数时,发⽣在内核中等待数据和复制数据的过程。
当调⽤recv()函数时,系统⾸先查是否有准备好的数据。
如果数据没有准备好,那么系统就处于等待状态。
当数据准备好后,将数据从系统缓冲区复制到⽤户空间,然后该函数返回。
在套接应⽤程序中,当调⽤recv()函数时,未必⽤户空间就已经存在数据,那么此时recv()函数就会处于等待状态。
Windows套接字程序使⽤“⽣产者-消费者”模式来解决上述问题。
在程序中,“⽣产者”读⼊数据,“消费者”根据需求对读⼊数据进⾏处理。
通常“⽣产者”和“消费者”存在于两个线程中,当“⽣产者”完成读⼊数据时,使⽤线程同步机制,例如设置⼀个事件通知“消费者”,“消费者”接收到这个事件后对读⼊的数据进⾏处理。
当使⽤socket()函数和WSASocket()函数创建套接字时,默认的套接字都是阻塞的。
这意味着当调⽤Windows Sockets API不能⽴即完成时,线程处于等待状态,直到操作完成。
并不是所有Windows Sockets API以阻塞套接字为参数调⽤都会发⽣阻塞。
例如,以阻塞模式的套接字为参数调⽤bind()、listen()函数时,函数会⽴即返回。
将可能阻塞套接字的Windows Sockets API调⽤分为以下四种:1.输⼊操作recv()、recvfrom()、WSARecv()和WSARecvfrom()函数。
以阻塞套接字为参数调⽤该函数接收数据。
gevent示例 -回复
gevent示例-回复Gevent示例:高效的Python并发编程解决方案引言:Python作为一种广泛应用的编程语言,在各个领域中都有着广泛的应用,然而,其中最著名的问题之一就是它的并发性能。
传统的Python解释器(CPython)由于全局解释器锁(GIL)的限制,在多线程并发执行时无法充分利用多核处理器的优势。
为了解决这个问题,许多开发者研发了不同的解决方案。
其中一种非常受欢迎和广泛使用的解决方案就是使用Gevent库。
在本文中,我们将一步一步回答关于Gevent的问题,并提供示例来说明其强大的并发编程能力。
第一部分:介绍Gevent1. 什么是Gevent?Gevent是一个基于协程的并发库,它基于libev或者libevent等事件驱动的库,提供了高效的并发解决方案。
它充分利用了Python中的生成器(generator)和eventlet库,使得编写高效的异步网络编程变得更加简单。
2. Gevent与传统的Python并发库有什么不同?传统的Python并发库,如threading和multiprocessing,通过使用线程或者进程来实现并发。
然而,由于GIL的存在,它们无法充分利用多核处理器的优势。
相比之下,Gevent使用协程,不需要线程或者进程切换的开销,避免了GIL的限制,从而提供了更高的效率和吞吐量。
第二部分:使用Gevent的基本步骤1. 安装Gevent要使用Gevent,首先需要安装它。
可以通过pip安装Gevent,使用以下命令:pip install gevent2. 导入必要的库在编写使用Gevent的代码之前,需要先导入相应的库。
常用的导入语句如下:pythonimport geventfrom gevent import monkeymonkey.patch_all()这里的monkey.patch_all()方法是必须的,它会自动替换Python标准库中的一些阻塞式的IO操作,使它们变得非阻塞,从而避免了协程的阻塞。
非阻塞套接字
非阻塞套接字非阻塞套接字(Non-blockingSocket)是一种网络编程中的重要概念,它的出现可以有效地解决网络通信中的一些瓶颈问题,提高程序的效率和响应速度。
本文将从以下几个方面详细介绍非阻塞套接字的概念、原理、应用及相关技术。
一、非阻塞套接字的概念在网络编程中,当一个程序调用套接字进行网络通信时,如果此时网络出现了阻塞情况,例如数据传输过程中网络发生延迟或者接收方未及时处理数据等,那么程序就会被阻塞,无法继续执行下去。
这种情况下,如果程序继续等待网络恢复正常,那么就会浪费大量的时间和资源,导致程序效率低下。
为了解决这个问题,非阻塞套接字应运而生。
非阻塞套接字是一种能够在网络出现阻塞时不会阻塞程序的套接字。
它的主要特点是:当程序调用非阻塞套接字进行网络通信时,如果网络出现阻塞,程序会立即返回,而不会一直等待网络恢复正常。
这样,程序就可以利用这段时间执行其他任务,提高效率。
二、非阻塞套接字的原理非阻塞套接字的实现原理主要涉及两个方面:非阻塞 I/O 和事件驱动机制。
1. 非阻塞 I/O在传统的阻塞 I/O 模型中,当程序调用套接字进行网络通信时,如果网络出现阻塞,程序会一直等待网络恢复正常。
而在非阻塞 I/O模型中,程序调用套接字进行网络通信时,如果网络出现阻塞,程序会立即返回一个错误码,例如 EWOULDBLOCK 或 EAGAIN 等。
这样,程序就可以利用这段时间进行其他任务,提高效率。
2. 事件驱动机制在非阻塞套接字中,程序调用套接字进行网络通信时,如果网络出现阻塞,程序不会一直等待网络恢复正常,而是通过事件驱动机制,等待网络可写或可读的事件发生。
当网络可写或可读时,程序再次调用套接字进行网络通信,从而实现非阻塞通信。
三、非阻塞套接字的应用非阻塞套接字在网络编程中有广泛的应用,主要体现在以下几个方面:1. 多路复用多路复用是指在一个进程中同时监听多个套接字,当其中任意一个套接字可读或可写时,程序就可以立即进行相应的操作。
Socket详解之阻塞非阻塞
这里不打算系统地介绍socket或者WinSock的知识。
首先介绍WinSock API函数,讲解阻塞/非阻塞的概念;然后介绍socket的使用。
APISocket接口是网络编程(通常是TCP/IP协议,也可以是其他协议)的API。
最早的Socket 接口是Berkeley接口,在Unix小小操作系统中实现。
WinSock也是一个基于Socket模型的API,在Microsoft Windows操作系统类中使用。
它在Berkeley接口函数的基础之上,还增加了基于消息驱动机制的Windows扩展函数。
只支持TCP/IP网络,增加了对更多协议的支持。
这里,讨论TCP/IP网络上的API。
Socket接口包括三类函数:第一类是WinSock API包含的Berkeley socket函数。
这类函数分两部分。
第一部分是用于网络I/O的函数,如accept、Closesocket、connect、recv、recvfrom、Select、Send、Sendto。
另一部分是不涉及网络I/O、在本地端完成的函数,如bind、getpeername、getsockname、getsocketopt、htonl、htons、inet_addr、inet_nton、ioctlsocket、listen、ntohl、ntohs、setsocketopt、shutdow、socket等第二类是检索有关域名、通信服务和协议等Internet信息的数据库函数,如gethostbyaddr、gethostbyname、gethostname、getprotolbyname、getprotolbynumber、getserverbyname、getservbyport。
第三类是Berkekley socket例程的Windows专用的扩展函数,如gethostbyname对应的WSAAsynGetHostByName(其他数据库函数除了gethostname都有异步版本),select对应的WSAAsynSelect,判断是否阻塞的函数WSAIsBlocking,得到上一次Windsock API错误信息的WSAGetLastError,等等。
各种网络架构的分类和分析
总结:模 型(1)是拓展select处理能力不错选择;模型(2)是模型(1)在爆发连接下的 调整版本;模型(3)是经典的reactor,epoll在该模型下 性能就已经很好,而select/poll仍 然存在爆发连接的拒绝连接情况;模型(4)(5)则是方便业务处理,对模型(3)进行多 线程调整的版本。带有 复杂业务处理的情况下推荐模型(5)。 根据测试显示,使用epoll的时候,模型(1)(2)相对(3)没有明显的性能优势,(1) 由于主线程两次的系统 调用,反而性能下降。
2、多路复用模型根据多路复用点、是否多线程分类: 以下各个模型依据选用select/poll/epoll又都细分为3类。下面个别术语采用select中的,仅
为说明。 (1)accept函数在多路复用函数之前,主线程在accept处阻塞,多个从线程在多路复用函 数处阻塞。主 线程和从线程通过管道通讯,主线程通过管道依次将连接的clientfd写入对应 从线程管道,从线程把管道的读端pipefd作为fd_set的第一一个描 述符,如pipefd可读,则读 数据,根据预定义格式分解出clientfd放入fd_set,如果clientfd可读,则read之后处理业 务。 此 方法可以避免select的fd_set上限限制,具体机器上select可以支持多少个描述符,可以 通过打印sizeof(fd_set)查看,我机器 上是512字节,则支持512×8=4096个。为了支持多余 4096的连接数,此模型下就可以创建多个从线程分别多路复用,主线程accept后平均放 入 (顺序循环)各个线程的管道中。创建5个从线程以其对应管道,就可以支持2w的连接,足 够了。另一一方面相对与单线程的select,单一一连接可读的时 候,还可以减少循环扫描fd_set 的次数。单线程下要扫描所有fd_set(如果再最后),该模型下,只需要扫描所在线程的 fd_set就可。 【说明:也就是主线程listen,接收fd后用pipe发给后端在等待pipe read端的从线程,从线 程可以用select等待这个pipe可读,和接收到的fd的网络io事件】
阻塞与非阻塞
1、阻塞赋值操作符用等号(即= )表示。
“阻塞”是指在进程语句(initial和always)中,当前的赋值语句阻断了其后的语句,也就是说后面的语句必须等到当前的赋值语句执行完毕才能执行。
而且阻塞赋值可以看成是一步完成的,即:计算等号右边的值并同时赋给左边变量。
例如:当执行“x=next_x;”时,x会立即的到next_x的值。
而下一句“y=x;”必须等到“x=next_x;”执行完毕才能被执行。
由于这两条语句都没有延迟(相当于导线),导致他们的等价语句为“y=next_x;”。
赋值是实时的,计算完右面的马上赋值给左边的,然后再执行下一句,操作时串行的,且在一个alway内完成。
2、非阻塞赋值操作符用小于等于号(即<= )表示。
“非阻塞”是指在进程语句(initial和always)中,当前的赋值语句不会阻断其后的语句。
非阻塞语句可以认为是分为两个步骤进行的:①计算等号右边的表达式的值,(我的理解是:在进入进程后,所有的非阻塞语句的右端表达式同时计算,赋值动作只发生在顺序执行到当前非阻塞语句那一刻)。
②在本条赋值语句结束时,将等号右边的值赋给等号左边的变量。
例如:当执行“x<=next_x;”时,并不会阻断语句“y<=x;”的执行。
因此,语句“y<=x;”中的x的值与语句“x<=next_x;”中的x的值不同:语句“y<=x;”中的x是第一个D触发器的初值(Q0)。
而语句“x<=next_x;”中的x的值是D触发器经过一个同步脉冲后的输出值(Q1)。
基于此这个进程产生了与阻塞赋值进程截然不同的结果,即:产生了移位寄存器的效果,next_x à x à y。
简单理解就是,阻塞赋值是按需执行,非阻塞赋值是并行执行。
为了更好地理解上述要点,我们需要对Verilog 语言中的阻塞赋值和非阻塞赋值的功能和执行时间上的差别有深入的了解。
为了解释问题方便下面定义两个缩写字:RHS –方程式右手方向的表达式或变量可分别缩写为:RHS表达式或RHS变量。
非阻塞通信的基本概念-概述说明以及解释
非阻塞通信的基本概念-概述说明以及解释1.引言1.1 概述非阻塞通信是一种在计算机网络中常用的通信机制,它允许发送方在等待接收方响应时能够同时执行其他任务,从而提高系统的并发性和性能。
相对于阻塞通信,非阻塞通信能够更好地满足实时性要求高、资源利用率要求高的应用需求。
在阻塞通信中,发送方在发送消息后需要等待接收方的响应,这个等待过程会导致发送方的线程被阻塞,无法执行其他任务。
而非阻塞通信则通过使用异步通信模式,在发送消息后即使没有收到接收方的响应,发送方的线程也可以继续执行其他任务。
这种机制使得系统能够并发执行多个任务,提高整体的处理能力。
非阻塞通信的优势不仅表现在提高系统的并发性和性能上,还能够降低通信的延迟。
由于发送方无需一直等待接收方的响应,可以及时地处理其他任务,从而减少了消息传输的等待时间。
这对于实时性要求高的应用场景非常重要,例如在线游戏、金融交易等领域。
非阻塞通信在各个领域有着广泛的应用。
在计算机网络中,非阻塞通信被广泛应用于高性能计算、数据中心网络等场景中。
在分布式系统中,非阻塞通信被用于实现异步消息传递、事件驱动等机制。
在操作系统中,非阻塞通信被用于实现高效的进程间通信和线程间通信。
本文将深入探讨非阻塞通信的定义、原理、优势和应用,并对非阻塞通信的未来发展进行展望。
通过对非阻塞通信的基本概念的研究,我们可以更好地理解和应用非阻塞通信,在实际应用中提高系统的并发性和性能,满足各种实时性要求高的应用场景的需求。
1.2 文章结构文章结构部分的内容可以包括以下内容:文章结构部分旨在介绍整篇文章的组织结构和各个章节的内容概要。
通过清晰地展示文章的框架,读者可以更好地理解文章的结构和逻辑关系。
本篇文章的结构主要分为引言、正文和结论三个部分。
引言部分(Introduction)将在文章开头引起读者的兴趣,概述非阻塞通信的基本概念和重要性。
该部分还将介绍文章的结构和目的。
正文部分(Main Body)是本文的核心部分,用于详细解释非阻塞通信的定义和原理,以及非阻塞通信的优势和应用。
阻塞队列与非阻塞队列
阻塞队列与⾮阻塞队列阻塞队列阻塞队列(BlockingQueue)是⼀个⽀持两个附加操作的队列。
这两个附加的操作是:在队列为空时,获取元素的线程会等待队列变为⾮空。
当队列满时,存储元素的线程会等待队列可⽤。
阻塞队列常⽤于⽣产者和消费者的场景,⽣产者是往队列⾥添加元素的线程,消费者是从队列⾥拿元素的线程。
阻塞队列就是⽣产者存放元素的容器,⽽消费者也只从容器⾥拿元素。
⽅法\处理⽅式抛出异常返回特殊值⼀直阻塞超时退出插⼊⽅法add(e)offer(e)put(e)offer(e,time,unit)移除⽅法remove()poll()take()poll(time,unit)检查⽅法element()peek()不可⽤不可⽤抛出异常:是指当阻塞队列满时候,再往队列⾥插⼊元素,会抛出IllegalStateException(“Queue full”)异常。
当队列为空时,从队列⾥获取元素时会抛出NoSuchElementException异常。
返回特殊值:插⼊⽅法会返回是否成功,成功则返回true。
移除⽅法,则是从队列⾥拿出⼀个元素,如果没有则返回null⼀直阻塞:当阻塞队列满时,如果⽣产者线程往队列⾥put元素,队列会⼀直阻塞⽣产者线程,直到拿到数据,或者响应中断退出。
当队列空时,消费者线程试图从队列⾥take元素,队列也会阻塞消费者线程,直到队列可⽤。
超时退出:当阻塞队列满时,队列会阻塞⽣产者线程⼀段时间,如果超过⼀定的时间,⽣产者线程就会退出。
JDK7提供了7个阻塞队列。
分别是ArrayBlockingQueue :⼀个由数组结构组成的有界阻塞队列。
LinkedBlockingQueue :⼀个由链表结构组成的有界阻塞队列。
PriorityBlockingQueue :⼀个⽀持优先级排序的⽆界阻塞队列。
DelayQueue:⼀个使⽤优先级队列实现的⽆界阻塞队列。
SynchronousQueue:⼀个不存储元素的阻塞队列。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
在线学习好工作/Gevent学习之阻塞与非阻塞gevent中一个很大的改进就是将阻塞IO改为非阻塞IO,比如gevent.socket.patch就是将项目中阻塞socket变为非阻塞,因此深刻理解网络IO 部分阻塞/非阻塞十分重要。
1.阻塞调用是指调用结果返回之前,当前线程会被挂起。
函数只有在得到结果之后才会返回1)connect阻塞2)接收数据阻塞2.非阻塞指在不能立刻得到结果之前,该函数不会阻塞当前线程,而会立刻返回1)接收数据非阻塞2)非阻塞面临的问题源码1.代码示例import loggingimport timeimport errnologging.basicConfig( level=logging.DEBUG ,format='%( name ) s : % ( message ) s ' , )if __name__ == '__main__':import socketip = ' localhost 'port = 58562logger = logging.getLogger ( ' client ' )# Connect to the serverlogger.debug( ' creating socket ' )s = socket.socket ( socket.AF_INET, socket.SOCK_STREAM ) logger.debug( ' connecting to server ' )s.setblocking(0)try:s.connect( ( ip , port ) )except socket.error , msg :if msg[0] != errno.EINPROGRESS :logger.debug( ' error ' )exit(1)#time.sleep(1)# Send the datamessage = ' Hello , world '#len_sent = s.send ( message )logger.debug( ' sending data: "%s"', message )while True :try:len_sent = s.send ( message )breakexcept socket.error, msg :if msg[0] != errno.EAGAIN:exit(1)# Receive a responselogger.debug( ' waiting for response ' )while True:try:response = s.recv( len_sent )breakexcept socket.error, msg:if msg[0] != errno.EAGAIN:exit(1)logger.debug( ' response from server: "%s"', response )# Clean uplogger.debug( ' closing socket ' )s.close()logger.debug( ' done ' )执行结果2.代码示例import loggingimport sysimport SocketServerimport timelogging.basicConfig(level=logging.DEBUG ,format='%( name ) s : % ( message ) s ' ,)class EchoRequestHandler ( SocketServer.BaseRequestHandler ) :def __init__( self , request , client_address , server ) :self.logger = logging.getLogger ( ' EchoRequestHandler ' )self.logger.debug( ' __init__ ' )SocketServer.BaseRequestHandler.__init__(self, request, client_address, server)returndef setup ( self ) :self.logger.debug( ' setup ' )return SocketServer.BaseRequestHandler.setup ( self )def handle ( self ) :self.logger.debug( ' handle ' )# Echo the back to the clientdata = self.request.recv ( 1024 )self.logger.debug( ' recv()->"%s"', data )self.request.send( data )returndef finish ( self ) :self.logger.debug( ' finish ' )return SocketServer.BaseRequestHandler.finish(self)class EchoServer(SocketServer.TCPServer):def __init__(self, server_address, handler_class=EchoRequestHandler):self.logger = logging.getLogger (' EchoServer ' )Self.logger.debug ('__init__')SocketServer.TCPServer.__init__(self, server_address, handler_class)returndef server_activate ( self ) :Self.logger.debug ( ' server_activate ' )SocketServer.TCPServer.server_activate ( self )returndef serve_forever ( self ) :self.logger.debug( ' waiting for reques t ' ) ( ' Handling requests , press <Ctrl-C> to quit ' )while True :self.handle_request()returndef handle_request ( self ) :Self.logger.debug ( ' handle_request ' )return SocketServer.TCPServer.handle_request ( self )def verify_request ( self , request , client_address ) :Self.logger.debug ( ' verify_request ( %s , %s )', request, client_address)return SocketServer.TCPServer.verify_request(self, request, client_address ) def process_request (self , request , client_address ) :Self.logger.debug ( ' process_request ( %s , %s ) ' , request , client_address )return SocketServer.TCPServer.process_request (self , request , client_address ) def server_close ( self ) :Self.logger.debug ( ' server_close ' )return SocketServer.TCPServer.server_close ( self )def finish_request ( self , request , client_address ) :self.logger.debug('finish_request ( %s , %s ) ' , request , client_address )return SocketServer.TCPServer.finish_request(self , request , client_address ) def close_request ( self , request_address ) :self.logger.debug ( ' close_request ( %s ) ' , request_address )return SocketServer.TCPServer.close_request ( self , request_address )if __name__ == '__main__' :import socketimport threadingaddress = ( ' localhost ' , 0 ) # let the kernel give us a portserver = EchoServer ( address , EchoRequestHandler )ip, port = server.server_address # find out what port we were givenlogger = logging.getLogger ( ' client ' )( ' Server on %s : %s ' , ip , port )server.serve_forever ()文章来源:麦子学院原文链接:/wiki/frame/block/。