并发编程 --- 线程补充2

线程

event事件

作用:用来控制线程的执行,

使用方法:

Event是threading中的一个类,调用里边的一些方法对线程进行一些操作。

e = Event()
在某一个线程中出现了e.wait()的时候,此时这个线程就不能执行,e.wait()可以在多个线程中。
接触e.wait()的方法是,在别的线程中使用e.set(),此时其他线程中的e.wait()的线程都可以继续运行。

例:
from threading import Event
from threading import Thread
import time
# 调用Event类实例化一个对象
e = Event()

# 若该方法出现在任务中,则为False,阻塞
# e.wait()  # False

# 若该方法出现在任务中,则将其他线程的Flase改为True,进入就绪态与运行态
# e.set()  # True


def light():
    print('红灯亮...')
    time.sleep(5)
    # 应该开始发送信号,告诉其他线程准备执行
    e.set()  # 将car中的False ---> True
    print('绿灯亮...')


def car(name):
    print('正在等红灯....')
    # 让所有汽车任务进入阻塞态
    e.wait()  # False
    print(f'{name}正在加速漂移....')


# 让一个light线程任务 控制多个car线程任务
t = Thread(target=light)
t.start()

for line in range(10):
    t = Thread(target=car, args=(f'童子军jason{line}号', ))
    t.start()

进程池与线程池

定义:线程池与进程池是用来控制当前程序允许进程/线程的数量。

问题:如果无限制的开启进程或线程,会将服务器卡崩。

作用:线程池与进程池的作用就是保证在硬件允许的范围内创建线程或进程的数量。

使用:

# 知识点一:(进程池与线程池的基本使用)
进程池:
from concurrent.futures import ProcessPoolExecutor

ProcessPoolExecutor(5)  # 5代表只能开启5个进程
ProcessPoolExecutor()   # 默认以CPU的个数限制进程数

线程池:
from concurrent.futures import ThreadPoolExecutor

ThreadPoolExecutor(5)  # 5代表只能开启5个进程
ThreadPoolExecutor()   # 默认以CPU个数 * 5限制线程数

# 知识点二:(利用进程池与线程池做的扩展)
pool.submit('传函数地址') # 异步提交任务
相当于下边的两步
t = Thread()
t.start()

# 会让所有线程池的任务结束后,才往下执行代码。
pool.shutdown()

# 知识点三:(回调函数:直接调用函数的返回值)
pool.submit(task, 1).add_done_callback(call_back)
被传函数的返回值,       将函数的返回值传给括号内的回调函数
注意:回调函数一定要写res.result(),因为不许通过res.result()才嫩刚拿到县城任务返回的结果。

# 例:
def task(res):
    print('线程任务开始了...')
    time.sleep(1)
    print('线程任务结束了...')
    return 123


# 回调函数
def call_back(res):
    print(type(res))
    # 注意: 赋值操作不要与接收的res同名
    res2 = res.result()
    print(res2)


for line in range(5):
    pool.submit(task, 1).add_done_callback(call_back)

print('hello')

协程

进程:资源单位

线程:执行单位

协程:为了在单线程下实现并发, 节约资源。

注意:协程不是操作系统的资源,他是程序起的名字,为了让单线程实现并发。

协程的目的:通过手动模拟操作系统 “多道技术” ,实现 切换 + 保存状态。为了让单个线程不停地切换去执行任务,让你第一个任务遇到IO操作了,会切换到另一个线程中进行操作,这样就可以使用一个线程就可以去完成之前需要几个线程才能完成的事情,但是在单线程计算密集行的情况下使用协程,这样做会让线程在计算任务之间来回切换,效率反而会更低。

协程的优点:在IO密集型的情况下,会提高效率

协程的缺点:在计算密集型的情况下,来回切换,反而效率会更低。

如何实现协程:切换 + 保存状态。

使用第三方模块:gevent

作用:可以帮助监听IO操作,并且切换。

使用gevent的目的:为了实现单线程下,实现遇到IO,实现 切换+保存状态。

from gevent import monkey
monkey.patch_all()  # 可以监听该程序下所有的IO操作
import time
from gevent import spawn, joinall  # 用于做切换 + 保存状态


def func1():
    print('1')
    # IO操作
    time.sleep(1)


def func2():
    print('2')
    time.sleep(3)


def func3():
    print('3')
    time.sleep(5)


start_time = time.time()

s1 = spawn(func1)
s2 = spawn(func2)
s3 = spawn(func3)

s2.join()  # 发送信号,相当于等待自己 (在单线程的情况下)
s1.join()
s3.join()
# 必须传序列类型
joinall([s1, s2, s3])

end_time = time.time()

print(end_time - start_time)

# 输出:
1
2
3
5.011829614639282
原文地址:https://www.cnblogs.com/whkzm/p/11735948.html