python 64式: 第4式、eventlet协程实现并发

#!/usr/bin/env python
# -*- coding: utf-8 -*-


from datetime import datetime

import eventlet


eventlet.monkey_patch(all=True)

from eventlet.green import urllib2

'''
关键:
1 eventlet:协程(绿色线程),一个线程内的伪并发方式
原理:是执行序列,有独立栈和局部变量,与其他协程共享全局变量
与线程区别:多个线程可同时执行,而同一时间内,只允许一个协程运行,所以无需考虑锁
好处:协程执行顺序由程序决定,若工作耗时,协程会让出CPU,充分利用CPU性能。非阻塞。
本质:协程休息时会保存当前寄存器,重新工作会恢复
适用: 一个用来处理和网络相关的python库函数,而且可以通过协程来实现并发

参考文档:
https://www.cnblogs.com/Security-Darren/p/4170031.html

2 绿化与猴子补丁
所谓”绿化”是指绿化后的Python环境支持绿色线程的运行模式。
Python原生的标准库不支持eventlet这种绿色线程之间互相让渡CPU控制权的执行模型,
为此eventlet开发者改写了部分Python标准库(自称”补丁“)。
如果想在应用中使用eventlet,需要显式地绿化自己要引入的模块。

猴子补丁,在运行时动态修改已有代码,而无需修改原始代码
使用:替换标准库中的组件,例如socket
用法
import eventlet
eventlet.monkey_patch()   # 默认不加任何参数的情况下,是所有可能的module都会被patch。
monkey_patch(all=True,os=None, select=None, 
socket=None,thread=None,time=None,psycopg=None)

3 urllib2:用于抓取网页并保存到本地。把URL做为请求被发送到服务端,读取
服务端的响应资源
urllib2.urlopen(url,data,timeout)
返回值:instance
data是发送给服务端的内容
参考: https://docs.python.org/2/library/urllib2.html

4 eventlet.GreenPool()
作用:提供了对greenthread支持,提供已定数量的绿色线程,实际
就是绿色线程池
class eventlet.greenpool.GreenPool(size=1000) 
imap(function,* iterables)
等同于: itertools.imap(function, **iterable),在并发
和内存使用上等同于starmap()
用于:处理文件

5  eventlet.GreenPile(size_or+pool=1000)
GreenPile:用于表示抽象的IO相关任务
spawn(func, *args, **kw):
运行func在自己的绿色线程中,结果可以通过迭代
绿色管道
参考:http://eventlet.net/doc/modules/greenpool.html#eventlet.greenpool.GreenPool.spawn_n

6 不论是gevent还是eventlet,因为不存在实际的并发,响应时间和没有并发区别不大。
所以所谓的并发应该是看
如果用了monkey_patch替换的模块换成并发的模块,才会带来这个影响

总结:
eventlet是通过将标准python模块替换为可并发的模块来实现并发
'''

URLS=["https://www.baidu.com/"]

def timeHelper(func):
    def wrapper(*args, **kwargs):
        try:
            start = datetime.now()
            info = "############ Start at: %s ##########" % (
                str(start))
            print info
            result = func(*args, **kwargs)
            end = datetime.now()
            diff = end - start
            info = "##### End at: %s, cost time: %s #####" % (
                str(end), str(diff))
            print info
            return result
        except Exception as ex:
            info = "Exception type is %s, message is %s" % (ex.__class__.__name__, ex)
            print info
    return wrapper

def getUrl(url):
    stream = urllib2.urlopen(url)
    result = stream.read()
    return result

@timeHelper
def batch(urls, batchNum):
    i = 0
    results = []
    tempUrls = []
    for url in urls:
        tempUrls.append(url)
        if (i + 1) % batchNum == 0:
            result = validGreenPile(tempUrls)
            results.extend(result)
            tempUrls = []
        i += 1
    if tempUrls:
        result = validGreenPile(tempUrls)
        results.extend(result)
    return results


@timeHelper
def batchPool(urls, batchNum):
    i = 0
    results = []
    tempUrls = []
    for url in urls:
        tempUrls.append(url)
        if (i + 1) % batchNum == 0:
            result = validGreenPool(tempUrls)
            results.extend(result)
            tempUrls = []
        i += 1
    if tempUrls:
        result = validGreenPool(tempUrls)
        results.extend(result)
    return results


def validGreenPile(urls):
    pool = eventlet.GreenPool()
    pile = eventlet.GreenPile(pool)
    for url in urls:
        pile.spawn(getUrl, url)
    results = []
    for pl in pile:
        results.append(pl)
    return results


def validGreenPool(urls):
    pool = eventlet.GreenPool()
    results = []
    for result in pool.imap(getUrl, urls):
        results.append(result)
    return results


def getUrls(times):
    urls = []
    for i in range(times):
        urls.extend(URLS)
    return urls


def process():
    urls = getUrls(200)
    batchPool(urls, 100)

if __name__ == "__main__":
    process()

猜你喜欢

转载自blog.csdn.net/qingyuanluofeng/article/details/83118899