在Python中使用异步Socket编程性能测试

 更新时间:2014年06月25日 12:10:48   投稿:hebedich  
异步网络据说能极大的提高网络server的连接速度,所以打算写一个专题,来学习和了解异步网络.因为Python有个非常出名的异步Lib:Twisted,所以就用Python来完成.

OK,首先写一个python socket的server段,对开放三个端口:10000,10001,10002.krondo的例子中是每个server绑定一个端口,测试的时候需要分别开3个shell,分别运行.这太麻烦了,就分别用三个Thread来运行这些services.

import optparse 
import os 
import socket 
import time 
from threading import Thread 
import StringIO 
  
txt = '''1111 
2222 
3333 
4444 
''' 
  
  def server(listen_socket): 
  while True: 
    buf = StringIO.StringIO(txt) 
    sock, addr = listen_socket.accept() 
    print 'Somebody at %s wants poetry!' % (addr,) 
    while True: 
        try: 
          line = buf.readline().strip() 
          if not line: 
            sock.close() 
            break 
          sock.sendall(line) # this is a blocking call 
          print 'send bytes to client:%s' % line 
          #sock.close() 
        except socket.error: 
          sock.close() 
          break 
        time.sleep(1) #server和client连接后,server会故意每发送一个单词后等待一秒钟后再发送另一个单词 
  
  def main(): 
  ports = [10000, 10001, 10002] 
  for port in ports: 
    listen_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
    listen_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 
    addres = (str('127.0.0.1'), port) 
    listen_socket.bind(addres) 
    listen_socket.listen(5) 
    print "start listen at:%s" % (port,) 
    worker = Thread(target = server, args = [listen_socket]) 
    worker.setDaemon(True) 
    worker.start() 
  
  if __name__ == '__main__': 
  main() 
  while True: 
    time.sleep(0.1) #如果不sleep的话,CPU会被Python完全占用了 
    pass 

下面是一个client,没有才用异步网络,连接这个三个端口的server:

import socket 
  
  
if __name__ == '__main__': 
  ports = [10000, 10001, 10002] 
  for port in ports: 
    address = (str('127.0.0.1'), port) 
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
    sock.connect(address) 
    poem = '' 
    while True: 
      data = sock.recv(4) 
      if not data: 
        sock.close() 
        break 
      poem += data 
    print poem 

下面用异步的client来读取,代码如下:

import datetime, errno, optparse, select, socket 
  
def connect(port): 
  """Connect to the given server and return a non-blocking socket.""" 
  address = (str('127.0.0.1'), port) 
  sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
  sock.connect(address) 
  sock.setblocking(0) 
  return sock 
  
def format_address(address): 
  host, port = address 
  return '%s:%s' % (host or '127.0.0.1', port) 
  
if __name__ == '__main__': 
  ports = [10000, 10001, 10002] 
  start = datetime.datetime.now() 
  
  sockets = map(connect, ports) 
  poems = dict.fromkeys(sockets, '') # socket -> accumulated poem  
  
  # socket -> task numbers 
  sock2task = dict([(s, i + 1) for i, s in enumerate(sockets)]) 
  sockets = list(sockets) # make a copy 
  
  while sockets: 
    #运用select来确保那些可读取的异步socket可以立即开始读取IO 
    #OS不停的搜索目前可以read的socket,有的话就返回rlist 
    rlist, _, _ = select.select(sockets, [], []) 
    for sock in rlist: 
      data = '' 
      while True: 
        try: 
          new_data = sock.recv(1024) 
        except socket.error, e: 
          if e.args[0] == errno.EWOULDBLOCK: 
            break 
          raise 
        else: 
          if not new_data: 
            break 
          else: 
            print new_data 
            data += new_data 
  
      task_num = sock2task[sock] 
      if not data: 
        sockets.remove(sock) 
        sock.close() 
        print 'Task %d finished' % task_num 
      else: 
        addr_fmt = format_address(sock.getpeername()) 
        msg = 'Task %d: got %d bytes of poetry from %s' 
        print msg % (task_num, len(data), addr_fmt) 
  
      poems[sock] += data 
  
  elapsed = datetime.datetime.now() - start 
  print 'Got poems in %s' % elapsed 

结果只需要4秒就完成了读取任务。效率是刚才同步socket的三倍。对客户端的异步改造主要有两点:

同步模式下,客户端分别创建socket;而在异步模式下,client开始就创建了所有的socket。
通过“sock.setblocking(0)”设置socket为异步模式。
通过Unix系统的select俩返回可读取IO
最为核心的是26行和29行。尤其是29行的select操作返回待读取socket的列表。

相关文章

  • python爬虫判断招聘信息是否存在的实例代码

    python爬虫判断招聘信息是否存在的实例代码

    在本篇文章里小编给大家整理的是一篇关于python爬虫判断招聘信息是否存在的实例代码,有兴趣的朋友们可以学习下。
    2020-11-11
  • Python使用plt.boxplot()函数绘制箱图、常用方法以及含义详解

    Python使用plt.boxplot()函数绘制箱图、常用方法以及含义详解

    箱线图一般用来展现数据的分布,如上下四分位值、中位数等,也可以直观地展示异常点,下面这篇文章主要给大家介绍了关于Python使用plt.boxplot()函数绘制箱图、常用方法以及含义详解的相关资料,需要的朋友可以参考下
    2022-08-08
  • Python中三元运算符的简洁性及多用途实例探究

    Python中三元运算符的简洁性及多用途实例探究

    这篇文章主要为大家介绍了Python中三元运算符的简洁性及多用途实例探究,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2024-01-01
  • 深入讲解Python编程中的字符串

    深入讲解Python编程中的字符串

    这篇文章主要介绍了Python编程中的字符串,包括字符串的格式化与三引号的使用等,需要的朋友可以参考下
    2015-10-10
  • Python读写unicode文件的方法

    Python读写unicode文件的方法

    这篇文章主要介绍了Python读写unicode文件的方法,涉及Python针对文件的读取及编码操作的相关技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-07-07
  • Python linecache.getline()读取文件中特定一行的脚本

    Python linecache.getline()读取文件中特定一行的脚本

    Python中使用标准库中的linecache中的getline方法可以从某个文件中读取出特定的一行。
    2008-09-09
  • pyd文件逆向的方法实现

    pyd文件逆向的方法实现

    pyd文件是由非 Python,其它编程语言编写编译生成的 Python 扩展模块,本文主要介绍了pyd文件逆向的方法实现,具有一定的参考价值,感兴趣的可以了解一下
    2024-03-03
  • Python matplotlib实战之气泡图绘制

    Python matplotlib实战之气泡图绘制

    气泡图是一种多变量的统计图表,可以看作是散点图的变形,这篇文章主要为大家介绍了如何使用Matplotlib绘制气泡图,需要的小伙伴可以参考下
    2023-08-08
  • python爬虫实例之获取动漫截图

    python爬虫实例之获取动漫截图

    这篇文章主要给大家介绍了关于python爬虫实例之获取动漫截图的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用python具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2020-05-05
  • 使用Python进行数据清洗和预处理的实现代码

    使用Python进行数据清洗和预处理的实现代码

    Python作为数据科学领域的热门编程语言,提供了丰富的库和工具来处理和清洗数据,本文将介绍如何使用Python进行数据清洗和预处理,并提供相应的代码示例,需要的朋友可以参考下
    2024-05-05

最新评论