博客
关于我
python-进程池与线程池,协程
阅读量:796 次
发布时间:2023-03-08

本文共 3562 字,大约阅读时间需要 11 分钟。

进程池与线程池是Python中实现并发执行的两种主要方式。并发执行可以让多个任务看起来同时运行,核心原理是切换+保存状态。需要注意的是,操作系统无法无限创建进程或线程,特别是当任务数量超过CPU核数时,若不合理配置进程池或线程池,反而可能降低效率。

进程池和线程池的主要作用是限制任务的并发执行数量。ProcessPoolExecutor用于进程池,默认最多创建4个进程;ThreadPoolExecutor用于线程池,默认最多创建CPU核数的5倍。两者的异步调用接口都支持submit任务和map操作,后者可代替for循环,代码更加简洁。

需要区分同步调用和异步调用:同步调用会阻塞当前线程,等待任务完成后才继续执行;异步调用则立即返回,任务并发执行。进程池和线程池的主要区别在于它们使用的资源类型:进程池创建进程,线程池创建线程。

以下是代码示例:

from concurrent.futures import ProcessPoolExecutor, ThreadPoolExecutorimport time, random, osdef get(url):    print('%s GET %s' % os.getpid(), url)    time.sleep(random.randint(1, 3))    response = requests.get(url)    return response.text if response.status_code == 200 else '下载失败'def parse(future):    time.sleep(1)    result = future.result()    print('%s 解析结果为 %s' % os.getpid(), len(result))if __name__ == '__main__':    urls = [        'https://www.baidu.com',        'https://www.sina.com.cn',        'https://www.tmall.com',        'https://www.jd.com',        'https://www.python.org',        'https://www.openstack.org',        'https://www.baidu.com',        'https://www.baidu.com',        'https://www.baidu.com',    ]        p = ProcessPoolExecutor(9)    start = time.time()        for url in urls:        future = p.submit(get, url)        future.add_done_callback(parse)        p.shutdown(wait=True)    print('主', time.time() - start)    print('主', os.getpid())

线程池和进程池在执行方式上相同,但线程池更适合I/O密集型任务,而进程池则适合计算密集型任务。map函数可以替代submit操作,简化代码。

以下是基于yield实现的协程示例:

import timedef func1():    for i in range(10000000):        i + 1def func2():    for i in range(10000000):        i + 1start = time.time()func1()func2()stop = time.time()print(stop - start)  # 1.675490379333496 秒

基于yield的协程实现:

import timedef func1():    while True:        print('func1')        time.sleep(5)        yielddef func2():    g = func1()    for i in range(10000000):        print('func2')        time.sleep(100)        next(g)start = time.time()func2()stop = time.time()print(stop - start)  # 26.000497秒

yield函数返回生成器对象,适用于单线程并发。

gevent是第三方库,通过绿色线程实现协程。其核心思想是自动切换协程执行,减少等待时间。需要在启动时导入monkey patch:

from gevent import monkey; monkey.patch_all()from gevent import spawn, joinallimport timedef play(name):    print('%s play 1' % name)    time.sleep(5)    print('%s play 2' % name)def eat(name):    print('%s eat 1' % name)    time.sleep(3)    print('%s eat 2' % name)start = time.time()g1 = spawn(play, 'lxx')g2 = spawn(eat, 'lxx')joinall([g1, g2])print('主', time.time() - start)

gevent支持socket并发:

from gevent import monkey; monkey.patch_all()from socket import *from gevent import spawndef communicate(conn):    while True:        try:            data = conn.recv(1024)            if len(data) == 0: break            conn.send(data.upper())        except ConnectionResetError:            break    conn.close()def server(ip, port, backlog=5):    server = socket(AF_INET, SOCK_STREAM)    server.bind((ip, port))    server.listen(backlog)    while True:        conn, client_addr = server.accept()        spawn(communicate, conn)if __name__ == '__main__':    g1 = spawn(server, '127.0.0.1', 8080)    g1.join()

线程池实现socket并发:

from threading import Thread, current_threadfrom socket import *def client():    conn = socket(AF_INET, SOCK_STREAM)    conn.connect(('127.0.0.1', 8080))    n = 0    while True:        msg = f'{current_thread().name} say hello {n}'        n += 1        conn.send(msg.encode('utf-8'))        data = conn.recv(1024)        print(data.decode('utf-8'))if __name__ == '__main__':    for _ in range(500):        t = Thread(target=client)        t.start()

协程与线程相比,能够更高效地利用CPU资源,特别是在I/O密集型任务中表现优异。

转载地址:http://uklfk.baihongyu.com/

你可能感兴趣的文章
python基础篇(4):range语句
查看>>
python基础篇(3):print()补偿知识点
查看>>
python基础篇(2):字符串扩展知识点
查看>>
python基础篇(1):type()
查看>>
python基础篇(15):闭包
查看>>
python基础篇(14):多态
查看>>
python基础篇(12):继承
查看>>
python基础篇(11):封装
查看>>
python基础篇(10):自定义包
查看>>
python基础篇(10):类、对象与构造方法
查看>>
python系列【仅供参考】:python斗地主
查看>>
Python基础教程(第2版 修订版) pdf
查看>>
python基础实践(四)
查看>>
Python基础学习笔记(九)常用数据类型转换函数
查看>>
Python基础学习参考(五):字符串和编码
查看>>
Python基础学习
查看>>
python基础变量之---集合
查看>>
python基础变量之---字典
查看>>
python基础变量之---列表
查看>>
python基础变量之---元组
查看>>