python基础之并发

一、多线程

示例代码1:简单多线程

import time
import threading


def foo(t):
    print("foo 开始")
    time.sleep(t)
    print("foo 结束")

start = time.time()
t_list = []
for i in range(100):
    t = threading.Thread(target=foo, args=(2,)) # 注意,如果只有一个参数,必须有逗号,表明是一个元组
    t.start()
    t_list.append(t)

for t in t_list:
    t.join()

print(f"耗时{time.time() - start}秒")

示例代码2:互斥锁

import time
import threading

Lock = threading.Lock()


def addNum():
    global num  # 在每个线程中都获取这个全局变量
    # 上锁
    Lock.acquire()
    t = num - 1
    time.sleep(0.0001)
    num = t
    Lock.release()
    # 放锁


num = 100  # 设定一个共享变量
thread_list = []
for i in range(100):
    t = threading.Thread(target=addNum)
    t.start()
    thread_list.append(t)
for t in thread_list:  # 等待所有线程执行完毕
    t.join()
print('Result: ', num)

示例代码3:线程池

import time
from concurrent.futures import ThreadPoolExecutor


def task(i):
    print(f'任务{i}开始!')
    time.sleep(i)
    print(f'任务{i}结束!')
    return i

start = time.time()
pool = ThreadPoolExecutor(3)

future_list = []
for i in range(1, 4):
    # 线程池技术实现异步,完成并发
    future = pool.submit(task, i)  # future对象内包含很多内容,如result()为返回值
    future_list.append(future)

pool.shutdown()  # 阻塞
print(f"耗时{time.time() - start}")

print(future_list)
print([future.result() for future in future_list]) # 打印返回值列表

总结

使用线程池来执行线程任务的步骤如下:

  1. 调用 ThreadPoolExecutor 类的构造器创建一个线程池。
  2. 定义一个普通函数作为线程任务。
  3. 调用 ThreadPoolExecutor 对象的 submit() 方法来提交线程任务。
  4. 当不想提交任何任务时,调用 ThreadPoolExecutor 对象的 shutdown() 方法来关闭线程
    池。

二、多进程

示例代码:

import multiprocessing
# multiprocessing.Process拥有和threading.Thread()同样的API
import time


def foo(t):
    print(f"任务{t} 开始")
    time.sleep(t)
    print(f"任务{t} 结束")


# 多进程主程序必须写在__main__内
if __name__ == '__main__':
    start = time.time()

    # 3 基于多进程的并发
    t_list = []
    for i in range(1, 6):
        t = multiprocessing.Process(target=foo, args=(i,))
        t.start()
        t_list.append(t)

    for t in t_list:
        t.join()

    print(f"耗时{time.time() - start}秒")
	

三、协程 asyncio

示例代码1:

import asyncio
import time


async def task(i):
    print(f"任务{i}启动")
    await asyncio.sleep(i)
    print(f"任务{i}结束")


start = time.time()
# 创建事件循环对象
loop = asyncio.get_event_loop()
# 构建协程对象列表
tasks = [task(1), task(2), task(3)]  # task(1):协程对象coroutine object
print("tasks[0]:", tasks[0])
# 启动运行
loop.run_until_complete(asyncio.wait(tasks))  # 阻塞等待所有的协程结束
print("cost timer:", time.time() - start)

示例代码2: 获取异步任务的结果,回调函数

import asyncio
import time


async def foo(i):
    print(f"任务{i}启动")
    await asyncio.sleep(i)
    print(f"任务{i} {i}秒结束")
    return i * i


def task2callback(ret):
    print("异步任务2的结果:", ret.result())


start = time.time()
# 创建事件循环对象
loop = asyncio.get_event_loop()
# 构建任务对象列表
tasks = [
    asyncio.ensure_future(foo(1)),
    asyncio.ensure_future(foo(2)),
    asyncio.ensure_future(foo(3)),
]  # task(1):asyncio.Task

for task in tasks:
	task.add_done_callback(task2callback)

# 启动运行
loop.run_until_complete(asyncio.wait(tasks))  # 阻塞等待所有的协程结束

for task in tasks:
    print(task.done(), task.result())

print("cost timer:", time.time() - start)

示例代码3:gather可以返回任务返回值

import asyncio
import time


async def foo(i):
    print(f"任务{i}启动")
    await asyncio.sleep(i)
    print(f"任务{i} {i}秒结束")
    return i * i


async def main():
    # 构建任务对象列表
    tasks = [
        asyncio.create_task(foo(1)),
        asyncio.create_task(foo(2)),
        asyncio.create_task(foo(3)),
    ]

    # 方式1
    # tasks[0].add_done_callback(lambda ret: print(ret.result()))
    #
    # await asyncio.wait(tasks)  # 阻塞
    #
    # for task in tasks:
    #     print(task.done(), task.result())

    # 方式2
    rets = await asyncio.gather(*tasks) # gather必须传入多个task对象,不能传入列表
    print(rets)


start = time.time()
asyncio.run(main())
print("cost timer:", time.time() - start)

示例代码4: aiohttp

import aiohttp
import asyncio


async def main():
    async with aiohttp.ClientSession() as session:
        async with session.get("http://httpbin.org/headers") as response:
            print(await response.text())


asyncio.run(main())

示例代码5:aiohttp 和 aiofiles

import asyncio
import aiohttp
import aiofiles

urls = ["https://img.lianzhixiu.com/uploads/allimg/202109/9999/d1eeaa0450.jpg",
        "https://img.lianzhixiu.com/uploads/allimg/202109/9999/6747451f08.jpg",
        "https://img.lianzhixiu.com/uploads/allimg/202108/9999/88abd53cc1.jpg"
        ]


async def aioDownload(url):
    # 发送请求
    # 得到图片内容
    # 保存到文件
    print("开始下载")
    name = url.rsplit("/", 1)[1]  # 从右边切一次,得到[1]位置的内容
    async with aiohttp.ClientSession() as session:  # 相当于requests
        async with session.get(url) as resp:  # 相当于resp = requests.get()
            # 请求回来了,aiofiles写入文件,
            async with aiofiles.open(name, mode='wb') as f:  # 创建文件
                await f.write(await resp.content.read())  # 读取内容是异步的,需要await挂起,resp.text()

    print("下载完成")


async def main():
    # 准备异步协程对象列表
    tasks = []

    for url in urls:
        task = asyncio.create_task(aioDownload(url))
        tasks.append(task)

    await asyncio.wait(tasks)


"""
========================================
主函数功能测试
========================================
"""
if __name__ == '__main__':
    # 一次性启动多个任务
    # asyncio.run(main())

    loop = asyncio.get_event_loop()
    loop.run_until_complete(main())

posted @ 2023-06-21 17:28  #缘起  阅读(60)  评论(0编辑  收藏  举报