pyhon 并发测试

1. thread 中join函数的解释  
```
1. .join方法的作用是阻塞主进程(挡住,无法执行join以后的语句),专注执行多线程。

2. 多线程多join的情况下,依次执行各线程的join方法,前头一个结束了才能执行后面一个。
```
```
eg:
#! usr/bin/python
#coding=utf-8

# 测试多线程中join的功能

import threading, time
def thread0():
    print 'start thread0: ' + time.strftime('%H:%M:%S') + "\n"
    time.sleep(3)
    print 'stop thread0: ' + time.strftime('%H:%M:%S') + "\n"
def thread1():
    print 'start thread1: ' + time.strftime('%H:%M:%S') + "\n"
    time.sleep(1)
    print 'stop thread1: ', time.strftime('%H:%M:%S') + "\n"
tsk = []
t0 = threading.Thread(target = thread0)
tsk.append(t0)
t1 = threading.Thread(target = thread1)
tsk.append(t1)
print 'no join: ' + time.strftime('%H:%M:%S') + "\n"
for tt in tsk:
    tt.start()
    #tt.join()

结果:no join函数时,线程1先于线程0结束,由于线程1sleep时间短
no join: 18:33:34

start thread0: 18:33:34

start thread1: 18:33:34

stop thread1:  18:33:35

stop thread0: 18:33:37
```
```
#! usr/bin/python
#coding=utf-8

# 测试多线程中join的功能

import threading, time
def thread0():
    print 'start thread0: ' + time.strftime('%H:%M:%S') + "\n"
    time.sleep(3)
    print 'stop thread0: ' + time.strftime('%H:%M:%S') + "\n"
def thread1():
    print 'start thread1: ' + time.strftime('%H:%M:%S') + "\n"
    time.sleep(1)
    print 'stop thread1: ', time.strftime('%H:%M:%S') + "\n"
tsk = []
t0 = threading.Thread(target = thread0)
tsk.append(t0)
t1 = threading.Thread(target = thread1)
tsk.append(t1)
print 'start join: ' + time.strftime('%H:%M:%S') + "\n"
for tt in tsk:
    tt.start()
    tt.join()

结果:阻塞线程1,待线程0执行完成才执行线程1

start thread0: 18:36:59

stop thread0: 18:37:02

start thread1: 18:37:02

stop thread1:  18:37:03
```
2. eventLet  
注:eventlet是python库函数,可以通过协程实现并发。所谓并发,就是开启了多个greenthread(绿色线程)   

相关概念:  
```
协程对比线程优点:  
 1. 顺序可控,完全是由程序控制执行的顺序,而通常多线程一旦启动,运行时序是没法预测的,因此通常会给测试所有的程序带来问题
 2.同一时间只有一个协程在运行,无需对全局变量进行加锁
```
在eventlet里,把“协程”叫做greenthread(绿色线程),主要依赖俩个库  
```
1、greenlet

  greenlet库是其并发的基础,eventlet库简单的对其进行封装之后,就构成了Green

2、select.epoll(或者epoll类似的库)

   select库中的epoll则是默认的网络通信模型,作用与协程的调度顺序等
```
几个主要API的理解:  
```
1、Greenthread Spawn(产生greenthread绿色线程)

  主要有3个函数可以创建绿色线程:

(1)spawn(func, *args, **kwargs)

   创建绿色线程去运行fun这个函数,后面的参数是传递给这个函数的参数。

   返回值是eventlet.GreenThread对象,这个对象可以用来接受func函数运行的返回值。

   在绿色线程池还没有满的情况下,绿色线程一被创建就会立刻执行。线程被创建出来,肯定是要有一定的任务要去执行,这里直接把函数当作参数传递进去,去执行一定的任务,就好像标准库中的线程用run()方法去执行任务一样。

(2)spawn_n(func, *args, **kwargs)

   这个函数和spawn()类似,不同的就是它没有返回值,因而更加高效,这种特性,使它也有存在的价值。

(3)spawn_after(seconds, func, *args, **kwargs)

   这个函数和spawn()基本上一样,都有一样的返回值,不同的是它可以限定在什么时候执行这个绿色线程,即在seconds秒之后,启动这个绿色线程。

2、Greenthread Control(控制greenthread)

  (1)sleep(seconds=0)

    中止当前的绿色线程,以允许其它的绿色线程执行

  (2)eventlet.GreenPool

    这是一个类,在这个类中用set集合来容纳所创建的绿色线程,并且可以指定容纳线程的最大数量(默认是1000个),它的内部是用Semaphore和Event这两个类来对池进行控制的,这样就构成了线程池。其中,有几个比较重要的方法:

    running(self):返回当前池中的绿色线程数

    free():返回当前池中仍可容纳的绿色线程数

    spawn()、spawn_n():创建新的绿色线程

    starmap(self, function, iterable) 和 imap(self, function, *iterables):

    前者实现的是从iterable中取出每一项作为function的参数来执行,后者则是分别从iterables中各取一项,作为function的参数去执行。

    如: imap(pow, (2,3,10), (5,2,3)) --> 32 9 1000        元祖

       starmap(pow, [(2,5), (3,2), (10,3)]) --> 32 9 1000   元祖列表

  (3)eventlet.GreenPile

    这也是一个类,而且是一个很有用的类,在它内部维护了一个GreenPool对象和一个Queue对象。

    这个GreenPool对象可以是从外部传递进来的,也可以是在类内部创建的,GreenPool对象主要是用来创建绿色线程的,即在GreenPile内部调用了GreenPool.spawn()方法。而Queue对象则是用来保存spawn()方法的返回值的,即Queue中保存的是GreenThread对象。并且它还实现了next()方法,也就意味着GreenPile对象具有了迭代器的性质。所以如果我们要对绿色线程的返回值进行操作的话,用这个类是再好不过的了。

  (4)eventlet.Queue(这个类不是很清楚,先写下来等后面通过实例用到的时候再来理解)

    说到队列就不得不画个类图了,基类是LightQueue,它实现了大部分的队列的常用方法。它是用collections做为实现队列的基本数据结构的。而且这个LightQueue的实现,不单单实现了存取操作,我觉得在本质上它实现了一个生产者和消费者问题,定义了两个set()类型的成员变量putters和getters,前者用来存放在队列满时,被阻塞的绿色线程,后者用来存放当队列空时,被阻塞的绿色线程。类中的putting()和getting()方法就是分别得到被阻塞的绿色线程的数量。

    Queue继承了LightQueue,并且又增加了它自己的两个方法:task_done()和join()。

    (1)、task_done()是被消费者的绿色线程所调用的,表示在这个项上的所有工作都做完了。

    (2)、join()是阻塞,直到队列中所有的任务都完成。LifoQueue和PriorityQueue是存放数据的两种不同的方式。
```
示例: 
```
import eventlet  
from eventlet.green import urllib2  
   
   
urls = [  
    "http://www.google.com/intl/en_ALL/images/logo.gif",  
    "https://wiki.secondlife.com/w/images/secondlife.jpg",  
    "http://us.i1.yimg.com/us.yimg.com/i/ww/beta/y3.gif",  
]  
   
   
def fetch(url):  
    return urllib2.urlopen(url).read()  
   
   
pool = eventlet.GreenPool(200) #创建绿色线程池对象,可以指定数量  
   
for body in pool.imap(fetch, urls): #协程根据指定要执行的函数依次执行获得url的信息  
    print("got body", len(body))
```
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

youyou9526

各位看官,给点下载积分吧

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值