- 浏览: 71737 次
- 性别:
- 来自: 北京
最新评论
-
xiayh04:
楼主好人!
Django书籍分享 -
winchun323:
感觉楼主,资料下载了!!!
ANDROID资料共享 -
tonyseek:
sydra 写道不是很懂python,鄙人是做java的,很奇 ...
Python单例模式 -
tterry:
没看出来怎么个劣法,莫非你说劣就劣?
避免劣化的python代码 -
edison0951:
Kabie 写道Singleton模式一般是用metaclas ...
Python单例模式
Benefits of Asynchronous Sockets and Linux epoll
The sockets shown in Example 2 are called blocking sockets, because the Python program stops running until an event occurs. The accept() call in line 16 blocks until a connection has been received from a client. The recv() call in line 19 blocks until data has been received from the client (or until there is no more data to receive). The send() call in line 21 blocks until all of the data being returned to the client has been queued by Linux in preparation for transmission.
When a program uses blocking sockets it often uses one thread (or even a dedicated process) to carry out the communication on each of those sockets. The main program thread will contain the listening server socket which accepts incoming connections from clients. It will accept these connections one at a time, passing the newly created socket off to a separate thread which will then interact with the client. Because each of these threads only communicates with one client, it is ok if it is blocked from proceeding at certain points. This blockage does not prohibit any of the other threads from carrying out their respective tasks.
The use of blocking sockets with multiple threads results in straightforward code, but comes with a number of drawbacks . It can be difficult to ensure the threads cooperate appropriately when sharing resources. And this style of programming can be less efficient on computers with only one CPU.
The C10K Problem discusses some of the alternatives for handling multiple concurrent sockets. One is the use of asynchronous sockets. These sockets don't block until some event occurs. Instead, the program performs an action on an asynchronous socket and is immediately notified as to whether that action succeeded or failed. This information allows the program to decide how to proceed. Since asynchronous sockets are non-blocking, there is no need for multiple threads of execution. All work may be done in a single thread. This single-threaded approach comes with its own challenges, but can be a good choice for many programs. It can also be combined with the multi-threaded approach: asynchronous sockets using a single thread can be used for the networking component of a server, and threads can be used to access other blocking resources, e.g. databases.
Linux 2.6 has a number of mechanisms for managing asynchronous sockets, three of which are exposed by the Python API's select , poll and epoll . epoll and poll are better than select because the Python program does not have to inspect each socket for events of interest. Instead it can rely on the operating system to tell it which sockets may have these events. And epoll is better than poll because it does not require the operating system to inspect all sockets for events of interest each time it is queried by the Python program. Rather Linux tracks these events as they occur, and returns a list when queried by Python. So epoll is a more efficient and scalable mechanism for large numbers (thousands) of concurrent socket connections, as shown in these graphs .
Asynchronous Socket Programming Examples with epoll
Programs using epoll often perform actions in this sequence:
- Create an epoll object
- Tell the epoll object to monitor specific events on specific sockets
- Ask the epoll object which sockets may have had the specified event since the last query
- Perform some action on those sockets
- Tell the epoll object to modify the list of sockets and/or events to monitor
- Repeat steps 3 through 5 until finished
- Destroy the epoll object
Example 3 duplicates the functionality of Example 2 while using asynchronous sockets. The program is more complex because a single thread is interleaving the communication with multiple clients.
- Line 1: The select module contains the epoll functionality.
- Line 13: Since sockets are blocking by default, this is necessary to use non-blocking (asynchronous) mode.
- Line 15: Create an epoll object.
- Line 16: Register interest in read events on the server socket. A read event will occur any time the server socket accepts a socket connection.
- Line 19: The connection dictionary maps file descriptors (integers) to their corresponding network connection objects.
- Line 21: Query the epoll object to find out if any events of interest may have occurred. The parameter "1" signifies that we are willing to wait up to one second for such an event to occur. If any events of interest occurred prior to this query, the query will return immediately with a list of those events.
- Line 22: Events are returned as a sequence of (fileno, event code) tuples. fileno is a synonym for file descriptor and is always an integer.
- Line 23: If a read event occurred on the socket server, then a new socket connection may have been created.
- Line 25: Set new socket to non-blocking mode.
- Line 26: Register interest in read (EPOLLIN) events for the new socket.
- Line 31: If a read event occurred then read new data sent from the client.
- Line 33: Once the complete request has been received, then unregister interest in read events and register interest in write (EPOLLOUT) events. Write events will occur when it is possible to send response data back to the client.
- Line 34: Print the complete request, demonstrating that although communication with clients is interleaved this data can be assembled and processed as a whole message.
- Line 35: If a write event occurred on a client socket, it's able to accept new data to send to the client.
- Lines 36-38: Send the response data a bit at a time until the complete response has been delivered to the operating system for transmission.
- Line 39: Once the complete response has been sent, disable interest in further read or write events.
- Line 40: A socket shutdown is optional if a connection is closed explicitly. This example program uses it in order to cause the client to shutdown first. The shutdown call informs the client socket that no more data should be sent or received and will cause a well-behaved client to close the socket connection from it's end.
- Line 41: The HUP (hang-up) event indicates that the client socket has been disconnected (i.e. closed), so this end is closed as well. There is no need to register interest in HUP events. They are always indicated on sockets that are registered with the epoll object.
- Line 42: Unregister interest in this socket connection.
- Line 43: Close the socket connection.
- Lines 18-45: The try-catch block is included because the example program will most likely be interrupted by a KeyboardInterrupt exception
- Lines 46-48: Open socket connections don't need to be closed since Python will close them when the program terminates. They're included as a matter of good form.
1 import socket, select 2 3 EOL1 = b'\n\n' 4 EOL2 = b'\n\r\n' 5 response = b'HTTP/1.0 200 OK\r\nDate: Mon, 1 Jan 1996 01:01:01 GMT\r\n' 6 response += b'Content-Type: text/plain\r\nContent-Length: 13\r\n\r\n' 7 response += b'Hello, world!' 8 9 serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 10 serversocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 11 serversocket.bind(('0.0.0.0', 8080)) 12 serversocket.listen(1) 13 serversocket.setblocking(0) 14 15 epoll = select.epoll() 16 epoll.register(serversocket.fileno(), select.EPOLLIN) 17 18 try: 19 connections = {}; requests = {}; responses = {} 20 while True: 21 events = epoll.poll(1) 22 for fileno, event in events: 23 if fileno == serversocket.fileno(): 24 connection, address = serversocket.accept() 25 connection.setblocking(0) 26 epoll.register(connection.fileno(), select.EPOLLIN) 27 connections[connection.fileno()] = connection 28 requests[connection.fileno()] = b'' 29 responses[connection.fileno()] = response 30 elif event & select.EPOLLIN: 31 requests[fileno] += connections[fileno].recv(1024) 32 if EOL1 in requests[fileno] or EOL2 in requests[fileno]: 33 epoll.modify(fileno, select.EPOLLOUT) 34 print('-'*40 + '\n' + requests[fileno].decode()[:-2]) 35 elif event & select.EPOLLOUT: 36 byteswritten = connections[fileno].send(responses[fileno]) 37 responses[fileno] = responses[fileno][byteswritten:] 38 if len(responses[fileno]) == 0: 39 epoll.modify(fileno, 0) 40 connections[fileno].shutdown(socket.SHUT_RDWR) 41 elif event & select.EPOLLHUP: 42 epoll.unregister(fileno) 43 connections[fileno].close() 44 del connections[fileno] 45 finally: 46 epoll.unregister(serversocket.fileno()) 47 epoll.close() 48 serversocket.close()
epoll has two modes of operation, called edge-triggered and level-triggered . In the edge-triggered mode of operation a call to epoll.poll() will return an event on a socket only once after the read or write event occurred on that socket. The calling program must process all of the data associated with that event without further notifications on subsequent calls to epoll.poll() . When the data from a particular event is exhausted, additional attempts to operate on the socket will cause an exception. Conversely, in the level-triggered mode of operation, repeated calls to epoll.poll() will result in repeated notifications of the event of interest, until all data associated with that event has been processed. No exceptions normally occur in level-triggered mode.
For example, suppose a server socket has been registered with an epoll object for read events. In edge-triggered mode the program would need to accept() new socket connections until a socket.error exception occurs. Whereas in the level-triggered mode of operation a single accept() call can be made and then the epoll object can be queried again for new events on the server socket indicating that additional calls to accept() should be made.
Example 3 used level-triggered mode, which is the default mode of operation. Example 4 demonstrates how to use edge-triggered mode. In Example 4, lines 25, 36 and 45 introduce loops that run until an exception occurs (or all data is otherwise known to be handled). Lines 32, 38 and 48 catch the expected socket exceptions. Finally, lines 16, 28, 41 and 51 add the EPOLLET mask which is used to set edge-triggered mode.
Example 4 1 import socket, select 2 3 EOL1 = b'\n\n' 4 EOL2 = b'\n\r\n' 5 response = b'HTTP/1.0 200 OK\r\nDate: Mon, 1 Jan 1996 01:01:01 GMT\r\n' 6 response += b'Content-Type: text/plain\r\nContent-Length: 13\r\n\r\n' 7 response += b'Hello, world!' 8 9 serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 10 serversocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 11 serversocket.bind(('0.0.0.0', 8080)) 12 serversocket.listen(1) 13 serversocket.setblocking(0) 14 15 epoll = select.epoll() 16 epoll.register(serversocket.fileno(), select.EPOLLIN | select.EPOLLET) 17 18 try: 19 connections = {}; requests = {}; responses = {} 20 while True: 21 events = epoll.poll(1) 22 for fileno, event in events: 23 if fileno == serversocket.fileno(): 24 try: 25 while True: 26 connection, address = serversocket.accept() 27 connection.setblocking(0) 28 epoll.register(connection.fileno(), select.EPOLLIN | select.EPOLLET) 29 connections[connection.fileno()] = connection 30 requests[connection.fileno()] = b'' 31 responses[connection.fileno()] = response 32 except socket.error: 33 pass 34 elif event & select.EPOLLIN: 35 try: 36 while True: 37 requests[fileno] += connections[fileno].recv(1024) 38 except socket.error: 39 pass 40 if EOL1 in requests[fileno] or EOL2 in requests[fileno]: 41 epoll.modify(fileno, select.EPOLLOUT | select.EPOLLET) 42 print('-'*40 + '\n' + requests[fileno].decode()[:-2]) 43 elif event & select.EPOLLOUT: 44 try: 45 while len(responses[fileno]) > 0: 46 byteswritten = connections[fileno].send(responses[fileno]) 47 responses[fileno] = responses[fileno][byteswritten:] 48 except socket.error: 49 pass 50 if len(responses[fileno]) == 0: 51 epoll.modify(fileno, select.EPOLLET) 52 connections[fileno].shutdown(socket.SHUT_RDWR) 53 elif event & select.EPOLLHUP: 54 epoll.unregister(fileno) 55 connections[fileno].close() 56 del connections[fileno] 57 finally: 58 epoll.unregister(serversocket.fileno()) 59 epoll.close() 60 serversocket.close()
Since they're similar, level-triggered mode is often used when porting an application that was using the select or poll mechanisms, while edge-triggered mode may be used when the programmer doesn't need or want as much assistance from the operating system in managing event state.
In addition to these two modes of operation, sockets may also be registered with the epoll object using the EPOLLONESHOT event mask. When this option is used, the registered event is only valid for one call to epoll.poll() , after which time it is automatically removed from the list of registered sockets being monitored.
Performance Considerations
Listen Backlog Queue Size
In Examples 1-4, line 12 has shown a call to the serversocket.listen() method. The parameter for this method is the listen backlog queue size. It tells the operating system how many TCP/IP connections to accept and place on the backlog queue before they are accepted by the Python program. Each time the Python program calls accept() on the server socket, one of the connections is removed from the queue and that slot can be used for another incoming connection. If the queue is full, new incoming connections are silently ignored causing unnecessary delays on the client side of the network connection. A production server usually handles tens or hundreds of simultaneous connections, so a value of 1 will usually be inadequate. For example, when using ab to perform load testing against these sample programs with 100 concurrent HTTP 1.0 clients, any backlog value less than 50 would often produce performance degradation.
TCP Options
The TCP_CORK option can be used to "bottle up" messages until they are ready to send. This option, illustrated in lines 34 and 40 of Examples 5, might be a good option to use for an HTTP server using HTTP/1.1 pipelining.
1 import socket, select 2 3 EOL1 = b'\n\n' 4 EOL2 = b'\n\r\n' 5 response = b'HTTP/1.0 200 OK\r\nDate: Mon, 1 Jan 1996 01:01:01 GMT\r\n' 6 response += b'Content-Type: text/plain\r\nContent-Length: 13\r\n\r\n' 7 response += b'Hello, world!' 8 9 serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 10 serversocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 11 serversocket.bind(('0.0.0.0', 8080)) 12 serversocket.listen(1) 13 serversocket.setblocking(0) 14 15 epoll = select.epoll() 16 epoll.register(serversocket.fileno(), select.EPOLLIN) 17 18 try: 19 connections = {}; requests = {}; responses = {} 20 while True: 21 events = epoll.poll(1) 22 for fileno, event in events: 23 if fileno == serversocket.fileno(): 24 connection, address = serversocket.accept() 25 connection.setblocking(0) 26 epoll.register(connection.fileno(), select.EPOLLIN) 27 connections[connection.fileno()] = connection 28 requests[connection.fileno()] = b'' 29 responses[connection.fileno()] = response 30 elif event & select.EPOLLIN: 31 requests[fileno] += connections[fileno].recv(1024) 32 if EOL1 in requests[fileno] or EOL2 in requests[fileno]: 33 epoll.modify(fileno, select.EPOLLOUT) 34 connections[fileno].setsockopt(socket.IPPROTO_TCP, socket.TCP_CORK, 1) 35 print('-'*40 + '\n' + requests[fileno].decode()[:-2]) 36 elif event & select.EPOLLOUT: 37 byteswritten = connections[fileno].send(responses[fileno]) 38 responses[fileno] = responses[fileno][byteswritten:] 39 if len(responses[fileno]) == 0: 40 connections[fileno].setsockopt(socket.IPPROTO_TCP, socket.TCP_CORK, 0) 41 epoll.modify(fileno, 0) 42 connections[fileno].shutdown(socket.SHUT_RDWR) 43 elif event & select.EPOLLHUP: 44 epoll.unregister(fileno) 45 connections[fileno].close() 46 del connections[fileno] 47 finally: 48 epoll.unregister(serversocket.fileno()) 49 epoll.close() 50 serversocket.close()
On the other hand, the TCP_NODELAY option can be used to tell the operating system that any data passed to socket.send() should immediately be sent to the client without being buffered by the operating system. This option, illustrated in line 14 of Example 6, might be a good option to use for an SSH client or other "real-time" application.
1 import socket, select 2 3 EOL1 = b'\n\n' 4 EOL2 = b'\n\r\n' 5 response = b'HTTP/1.0 200 OK\r\nDate: Mon, 1 Jan 1996 01:01:01 GMT\r\n' 6 response += b'Content-Type: text/plain\r\nContent-Length: 13\r\n\r\n' 7 response += b'Hello, world!' 8 9 serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 10 serversocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 11 serversocket.bind(('0.0.0.0', 8080)) 12 serversocket.listen(1) 13 serversocket.setblocking(0) 14 serversocket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) 15 16 epoll = select.epoll() 17 epoll.register(serversocket.fileno(), select.EPOLLIN) 18 19 try: 20 connections = {}; requests = {}; responses = {} 21 while True: 22 events = epoll.poll(1) 23 for fileno, event in events: 24 if fileno == serversocket.fileno(): 25 connection, address = serversocket.accept() 26 connection.setblocking(0) 27 epoll.register(connection.fileno(), select.EPOLLIN) 28 connections[connection.fileno()] = connection 29 requests[connection.fileno()] = b'' 30 responses[connection.fileno()] = response 31 elif event & select.EPOLLIN: 32 requests[fileno] += connections[fileno].recv(1024) 33 if EOL1 in requests[fileno] or EOL2 in requests[fileno]: 34 epoll.modify(fileno, select.EPOLLOUT) 35 print('-'*40 + '\n' + requests[fileno].decode()[:-2]) 36 elif event & select.EPOLLOUT: 37 byteswritten = connections[fileno].send(responses[fileno]) 38 responses[fileno] = responses[fileno][byteswritten:] 39 if len(responses[fileno]) == 0: 40 epoll.modify(fileno, 0) 41 connections[fileno].shutdown(socket.SHUT_RDWR) 42 elif event & select.EPOLLHUP: 43 epoll.unregister(fileno) 44 connections[fileno].close() 45 del connections[fileno] 46 finally: 47 epoll.unregister(serversocket.fileno()) 48 epoll.close() 49 serversocket.close()
发表评论
-
Python单例模式
2011-01-19 15:37 5101网上曾经看到过PYTHON的面试题中有一个是PYTHON的单例 ... -
避免劣化的python代码
2010-12-02 16:16 2427劣化代码: s = [] for i in seq: ... -
三行代码的快速排序
2010-08-05 14:58 0def qsort(L): if len(L) &l ... -
memcache
2010-03-25 10:17 0import cmemcached import MySQLd ... -
读写XML文件
2010-03-11 15:05 01 from xml.dom.minidom impo ... -
守护进程(Python)
2010-03-08 20:19 2242守护进程:通常被定义为一个后台进程,而且它不属于任何一个终 ... -
备份代码
2010-03-04 11:19 0class Outter: name = None ... -
memcache,多线程
2010-02-26 17:11 0import threading import urll ... -
两道比较复杂的轩辕互动面试题(Python实现)
2010-02-22 15:04 31401.平衡点问题 平衡点:比如int[] numbers = ... -
轩辕互动面试题目-----最大递增子序列(Python实现)
2010-02-12 10:46 2211数组A中存放很多数据,比如A={1,2,3,4,3,2,1,4 ... -
PYGAME初探
2010-01-29 16:09 1701这几天闲着无聊,想着自己编个小游戏来玩玩,看网上的大牛可是 ... -
Logging 模块的使用
2010-01-04 11:02 1070def initlog(): import lo ... -
(转)ASCII 到UNICODE再到UTF8
2009-12-23 13:54 2448从 ASCII 到 UTF-8 : 大话编码 话说当年,老美搞 ... -
(进阶)判断字符串中是否有汉字
2009-12-14 16:02 2361方式一:Regular Expressions a =u&qu ... -
wxPython + BOA
2009-09-05 19:12 4304最近公司要写个WINDOWS ...
相关推荐
How to use epoll A complete example in C How to use epoll A complete example in C How to use epoll A complete example in C How to use epoll A complete example in C
在Linux系统中,epoll是I/O多路复用技术的一种高效实现,它极大地改进了传统的轮询方式,尤其在处理大量并发连接时表现出色。本文将深入探讨如何在多线程环境中使用epoll进行程序设计,以提高系统的并行处理能力。 ...
在Linux系统中,epoll是I/O多路复用技术的一种高效实现,它提供了一种在高并发场景下处理大量文件描述符(file descriptors)的能力。这个“linux epoll的封装类”是为了简化epoll接口的使用,使得初学者能够更轻松...
Python中的epoll是用于处理高并发I/O操作的高效机制,尤其在服务器编程中非常关键。它是Linux内核提供的一个接口,主要用于解决多路复用I/O问题,比如网络编程中的socket通信。在这个"python-epoll-examples"压缩包...
使用Python做的epoll高效率服务器。使用平台:Linux,windows不支持
linux系统下,利用epoll接收串口助手发来的数据并打印。
Linux的epoll是一种I/O多路复用技术,主要用于高并发、高性能的网络服务中,如服务器端编程。epoll相比传统的select和poll有更高的效率和可扩展性,因为它使用了内核空间的数据结构,减少了系统调用的开销。 在...
Linux的epoll是一种I/O多路复用技术,它提供了高效、灵活的处理大量并发连接的方式。在传统的轮询模型中,系统会不断检查每个文件描述符的状态,而epoll则通过事件驱动的方式,只在有实际I/O操作时才进行处理,显著...
`epoll`是Linux内核提供的一种I/O多路复用技术,它极大地提高了处理大量并发连接的效率。而`socket`则是进行网络通信的基本接口,它可以用于TCP和UDP协议。本篇文章将深入探讨如何在Linux环境下使用`epoll`与`socket...
在Linux操作系统中,Epoll(Event Poll)是用于高并发I/O处理的一种高效机制,尤其适合于网络服务器的开发。Epoll模型相比传统的select、poll等I/O多路复用模型,具有更好的性能和可扩展性。这个"linux下Epoll模型...
在Python中开发高性能的网络服务器时,`epoll`是Linux系统提供的一种I/O多路复用技术。它允许程序同时监视多个文件描述符,一旦某个文件描述符就绪(例如,有数据可读或可写),`epoll`就会通知程序。这种方式提高了...
在Linux系统中,epoll是I/O复用技术的一种,它是基于事件驱动的高效I/O管理方式,尤其适合处理大量的并发连接。与传统的select和poll相比,epoll提供了更高的性能和更低的延迟,因为它可以实现水平触发和边缘触发两...
Linux下的epoll服务器是高性能网络编程中的重要组成部分,它提供了高效、可扩展的I/O多路复用机制。本文将详细解析如何利用epoll在Linux系统下构建TCP服务器,以及涉及的相关类和文件。 首先,`epoll`是Linux内核...
Linux下的epoll是一种高效、可扩展的I/O多路复用技术,主要用于处理大量并发连接。它是基于事件驱动的I/O模型,适用于高并发服务器,如Web服务器、数据库服务器等。在epoll中,系统会监控一组文件描述符,当这些文件...
linux epoll 概念、优缺点、io复用 、脑图、Linux下的服务器模型:
### Linux 下 epoll 网络模型介绍 在深入探讨 Linux 下的 epoll 模型之前,我们先了解一下 epoll 的背景以及它为何成为 Linux 内核中 I/O 多路复用的关键技术之一。 #### 1. epoll 的背景与优势 早期 Linux 内核...
在Linux系统中,`epoll`是用于I/O多路复用的一种高效机制,尤其适合高并发、大连接数的网络服务。`epoll`在传统的`poll`和`select`基础上进行了优化,解决了它们在处理大量文件描述符时效率低下的问题。本篇文章将...
在Linux系统中,epoll是一种I/O事件通知机制,它被设计用来替代传统的select和poll函数,以提高在高并发环境下的性能。epoll的主要优点在于它的效率和可扩展性,使得它成为处理大量并发连接的理想选择,尤其适用于...
Windows 完成端口与 Linux epoll 技术简介 Windows 完成端口与 Linux epoll 技术是两种常见的高性能 I/O 模型,在 Windows 和 Linux 平台上广泛应用于开发高性能的网络服务程序。下面我们将详细介绍 Windows 完成...
【标题】:基于Linux Epoll机制的用电信息采集系统设计 【描述】:该文档讨论了如何利用Linux的Epoll机制构建一个用电信息采集系统,旨在适应现代化电力发展需求,提高用电管理的实时化程度。 【标签】:Linux操作...