博客
关于我
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/

你可能感兴趣的文章
Python3之写入Excel文档(xlsxwriter)
查看>>
Python3之打印操作打印流重定向(下)
查看>>
python3判断字典、列表、元组为空以及字典是否存在某个key的方法
查看>>
Python3利用pymysql操作 MySQL
查看>>
python3处理json文件中含有中文dumps的应用
查看>>
Python3子进程输出
查看>>
Python3学习笔记3,变量、运算符
查看>>
Python3学习笔记(urllib模块的使用)
查看>>
python3安装scapy_Linux下安装scapy-python3
查看>>
python3实现socket通信
查看>>
Python关于numpy.transpose函数详细解析附代码
查看>>
Python3导入自定义模块的3种方式
查看>>
python3打开txt文件_使用Python 3从文本文件读取句子并添加到列表中
查看>>
python3爬虫抓取智联招聘职位信息代码
查看>>
Python3爬虫数据入数据库---把爬取到的数据存到数据库,带数据库去重功能
查看>>
python3的 pymysql把mysqldb库取代了,让python 3支持mysqldb的解决方法
查看>>
Python3笔记——IDE的选择
查看>>
python3简单使用requests 用户代理,cookie池
查看>>
Python3组播通信编程实现教程(发送者+接收者)
查看>>
Python3编写网络爬虫10-数据存储方式三-CSV文件存储
查看>>