补充点
当你知道锁的使用必须释放锁时,实际上你在操作锁的时候极容易发生死锁(整个程序都被卡住和阻塞)。
[En]
When you know that the use of the lock must release the lock, in fact, you are extremely prone to deadlock when you operate the lock (the whole program is jammed and blocked).
from threading import Thread, Lock
import time
mutexA = Lock()
mutexB = Lock()
类只要加括号多次 产生的肯定是不同的对象
如果要实现多个圆括号,请等到相同的对象单例模式<details><summary>*<font color='gray'>[En]</font>*</summary>*<font color='gray'>If you want to implement multiple parentheses, wait until the same object singleton pattern</font>*</details>
class MyThead(Thread):
def run(self):
self.func1()
self.func2()
def func1(self):
mutexA.acquire()
print('%s 抢到A锁'% self.name) # 获取当前线程名
mutexB.acquire()
print('%s 抢到B锁'% self.name)
mutexB.release()
mutexA.release()
def func2(self):
mutexB.acquire()
print('%s 抢到B锁'% self.name)
time.sleep(2)
mutexA.acquire()
print('%s 抢到A锁'% self.name) # 获取当前线程名
mutexA.release()
mutexB.release()
if __name__ == '__main__':
for i in range(10):
t = MyThead()
t.start()
递归锁的特点:
可以被连续的acquire和release
但锁只能被第一个执行上述操作的人抢走。[En]
But the lock can only be grabbed by the first one to do the above.
它的内部有一个计数器 每acquire一次计数加一 每realse一次计数减一
只要计数不为0 那么其他人都无法抢到该锁
代码只需要将上述死锁的
mutexA = Lock()
mutexB = Lock()
换成
mutexA = mutexB = RLock()
这样死锁的程序就可以正常运行下去
信号量可能对应于不同阶段的不同技术点。在并发编程中,信号量指的是锁!
[En]
Semaphores may correspond to different technical points at different stages. In concurrent programming, semaphores refer to locks!
信号量和互斥量的比较:信号量可以看作多个坑,互斥量只能是一个坑!
[En]
Comparison between semaphores and mutexes: semaphores can be regarded as multiple pits, mutexes can only be one pit!
信号量的具体语法:
from threading import Thread, Semaphore # 信号量的模块
import time,random
sm = Semaphore(5) # 表示同时开设5个坑位(互斥锁只开设一个)
def task(name):
sm.acquire() # 加锁
print('%s正在蹲坑'%name)
time.sleep(random.randint(1,3)) # 蹲坑时间不等
sm.release() # 释放锁
if __name__ == '__main__':
for i in range(20): # 20个人去抢5个厕所
t = Thread(target=task,args=(i,))
t.start()
主进程/线程等待子进程/线程运行结束时,我们使用的是join方法!
而需要子进程/线程之间的相互的等待结束,需要用到event事件
from threading import Thread,Event
import time
1.先产生一个event对象
event = Event()
def person():
print('你来了')
time.sleep(2)
event.set() # 2.发送信号,表示我执行完毕了,你可以结束了
def my():
event.wait() # 3.接收到信号,好的我开始执行
print('我走了')
if __name__ == '__main__':
t = Thread(target=person)
t1 = Thread(target=my)
t1.start()
t.start()
池是用来保证计算机硬件安全的情况下最大限度的利用计算机,它降低了程序运行的效率但是保证了计算机硬件的安全,从而让你的程序正常的运行!!
1.导入进程池/线程池模块
from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor
import time
2.创建一个线程池对象,该对象括号内不传参数,默认是开设当前cpu个数*5的线程
pool = ThreadPoolExecutor(5) # 传入参数5,表示池子里固定创建了5个线程,这5个线程不会重复创建和销毁
def task(name):
print('%s来了'% name)
time.sleep(2)
3.朝池子中提交任务,第一个参数是函数名,第二个参数是函数需要传入的参数
"""
同步提交:提交任务之后原地等待返回结果,不往下执行任务
异步提交:提交任务之后不原地等待返回结果,继续往下执行
"""
pool.submit(task,'zhang') # 注意:这里的提交是一个异步提交
print('主')
优化
list = []
for i in range(20): # 向池子中提交20个任务。池子中只有5个线程
res = pool.submit(task,i) # 池方法异步提交之后有一个返回值,该返回值是一个future对象
# print(res.result()) # 该对象有一个result方法,可以用来返回对应线程函数的返回值,没有返回值则返回none
# result方法的使用使得submi异步提交变成了同步提交
list.append(res)
如果想等待所有的线程全部执行完毕,在往下执行代码,可以使用池的shutdown方法
pool.shutdown() # shutdown的作用是等待所有线程池运行完毕,再关闭所有线程池往下运行
for i in list:
print(i.result())
基本同线程池,不同的是以下部分:
1.导入进程池/线程池模块
from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor
import time,os
pool = ProcessPoolExecutor(5) # 不传默认是cpu的个数
def task(name):
print('%s来了'% name)
time.sleep(2)
call_back函数里面需要传一个参数,该参数就是res(一个future对象)
def call_back(n):
# 可以通过n.result()的方法获取task函数的返回值
print(n.result())
if __name__ == '__main__':
for i in range(20):
# add_done_callback方法是给submit这个异步提交添加一个回调机制,完成任务之后立刻回调结果,方法的参数是一个函数
res = pool.submit(task, i).add_done_callback(call_back)
协程其实就是一种在单线程下实现并发的操作,程序猿通过检测自己写的代码,一旦遇到了IO操作的代码,我们就编写代码进行切换,这样使得cpu一直处于运行状态,提高程序的运行效率!
gevent模块的引用时为了使得函数之间不断的切换+保存状态!!
"""
使用协程,就必须要我们通过代码实时检测程序是否进入到了IO操作,如果进入了IO操作,
就进行快速的切换,以此来实现并发的效果,提升程序的运行效率
"""
1.导入gevent模块的spawn模块,该模块是用来监测函数里面的IO操作的,但是spawn模块是无法监测一些常见的IO操作的
因此,需要导入gevent模块中的monkey模块,以此来监测所有的IO操作
from gevent import monkey,spawn
monkey.patch_all() # 猴子补丁
import time
def func1():
print('hhh')
time.sleep(2)
print('lalala')
def func2():
print('wwww')
time.sleep(3)
print('结束')
start_time = time.time()
g1 = spawn(func1) # spawn括号里是需要启动监测的函数名,函数名后面可以加需要传入的参数
g2 = spawn(func2) # 该方法是异步提交,有一个返回值,如果没有join方法会自动往下执行代码,结束程序
g2.join() # 等待函数执行完在往下执行
g1.join()
print(time.time()-start_time)
Original: https://www.cnblogs.com/suncolor/p/16632422.html
Author: 等日落
Title: 进程、线程补充与协程相关介绍
原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/498583/
转载文章受原作者版权保护。转载请注明原作者出处!