python高级编程——锁
程序员文章站
2022-07-01 17:02:50
锁 在使用用的过程中需要导入threading模块的Lock类 使用锁: 当多个线程几乎同时修改某一个共享数据的时候,需要进行同步控制 线程同步能够保证多个线程安全访问竞争资源,最简单的同步机制是引入互 斥锁。 互斥锁为资源引入一个状态:锁定/非锁定。 锁的语法 创建锁、锁定锁、释放锁 在锁定锁的过 ......
锁
在使用用的过程中需要导入threading模块的lock类
使用锁:
当多个线程几乎同时修改某一个共享数据的时候,需要进行同步控制
线程同步能够保证多个线程安全访问竞争资源,最简单的同步机制是引入互 斥锁。
互斥锁为资源引入一个状态:锁定/非锁定。
锁的语法
创建锁、锁定锁、释放锁
from threading import lock # 创建锁 mutex = lock() # 获取锁(上锁) mutex.acquire() # 释放锁(解锁) mutex.release()
在锁定锁的过程中acquire()方法可以接受一个blocking参数,
如果设定blocking为true,则当前线程会堵塞,直到获取到这个锁为止(如果没有 指定,那么默认为true)
如果设定blocking为false,则当前线程不会堵塞
上锁和解锁的过程(假设是多线程调度):
这个锁一般是为共享资源服务的,即多个线程同时使用共享资源。这个锁同一时间只能有一个线程调度,其他线程阻塞,只有当前调度的线程释放这个锁,阻塞的线程才能调度。
锁的优点:
确保了某段关键代码只能有一个线程从头到尾完整的执行。
锁的缺点:
组织了多线程的并发执行,包含锁的某段代码实际上只能以单线程模式执行,效率就大大的降低了;代码中可能存在多个锁,如果多个线程拥有多个锁,容易造成死锁。
死锁的现象(实例):
# 死锁 两者都没有释放对方需要的锁,而释放的条件恰好是获取对方释放所需要的锁 # 线程1 class mythread1(threading.thread): def __init__(self): super().__init__() def run(self): # 线程1获取a锁 if mutexa.acquire(): print(self.name+"-----do1---up-----") sleep(1) # 此时线程2获取了b锁,需要等待线程2释放b锁 if mutexb.acquire(): print(self.name + "-----do1---down-----") mutexb.release() mutexa.release() # 线程2 class mythread2(threading.thread): def __init__(self): super().__init__() def run(self): # 线程2获取b锁 if mutexb.acquire(): print(self.name + "-----do2---up-----") sleep(1) # 此时线程1获取了a锁,需要等待线程1释放a锁 if mutexa.acquire(): print(self.name + "-----do2---down-----") mutexa.release() mutexb.release() mutexa = threading.lock() mutexb = threading.lock() if __name__ == '__main__': # 线程1和线程2同时执行 t1 = mythread1() t2 = mythread2() t1.start() t2.start()
避免死锁的方法:(银行家算法,看实例)
# 银行家算法 class task1(threading.thread): def __init__(self): super().__init__() def run(self): while true: if lock1.acquire(): print("task1".center(20, "-")) sleep(0.5) lock2.release() class task2(threading.thread): def __init__(self): super().__init__() def run(self): while true: if lock2.acquire(): print("task2".center(20, "-")) sleep(0.5) lock3.release() class task3(threading.thread): def __init__(self): super().__init__() def run(self): while true: if lock3.acquire(): print("task3".center(20, "-")) sleep(0.5) lock1.release() lock1 = threading.lock() lock2 = threading.lock() lock3 = threading.lock() lock2.acquire() lock3.acquire() t1 = task1() t2 = task2() t3 = task3() t1.start() t2.start() t3.start()
多进程与多线程比较及选择
是否采用多任务处理,取决于我们的任务类型
如果是计算密集型,需要大量的cpu资源进行运算,代码的运行效率至关重 要,这样的任务一般不使用多线程进行,因为频繁的任务调度会拖慢cpu的
运算。
如果是io密集型,涉及到硬盘读写,网络读写等的任务,更多的时间在等待 io操作完成,这一类任务可以放到多线程或多进程中来进行。
单线程、多线程、多进程(一起实现同一代码的时间)
# 单线程、多线程、多进程的使用及不同 # 简单的求和 def fib(x): res = 0 for i in range(100000000): res += i*x return res # 阶乘 def fac(x): if x < 2: return 1 return x*fac(x-1) # 简单的求和 def sum(x): res = 0 for i in range(50000000): res += i*x return res # 函数列表 funcs = [fib, fac, sum] n = 100 class mythread(threading.thread): def __init__(self, func, args, name=""): super().__init__() self.name = name self.func = func self.args = args self.res = 0 def getresult(self): return self.res def run(self): print("starting ", self.name, " at: ", ctime()) self.res = self.func(self.args) print(self.name, "finished at: ", ctime()) def main(): nfuncs = range(len(funcs)) print("单线程".center(30, "*")) start = time() for i in nfuncs: print("start {} at: {}".format(funcs[i].__name__, ctime())) start_task = time() print(funcs[i](n)) end_task = time() print("任务 耗时:", end_task-start_task) print("{} finished at: {}".format(funcs[i].__name__, ctime())) end = time() print("单线程运行时间:", end-start) print("单线程结束:".center(30, "*")) print() print("多线程".center(30, "*")) start = time() threads = [] for i in nfuncs: # 一个线程绑定一个函数 t = mythread(funcs[i], n, funcs[i].__name__) threads.append(t) for i in nfuncs: # 同时启动线程 threads[i].start() for i in nfuncs: threads[i].join() print(threads[i].getresult()) end = time() print("多线程运行时间:", end-start) print("多线程结束:".center(30, "*")) print() print("多进程".center(30, "*")) start = time() process_list = [] for i in nfuncs: # 一个进程绑定一个函数 t = process(target=funcs[i], args=(n, )) process_list.append(t) for i in nfuncs: # 同时启动进程 process_list[i].start() for i in nfuncs: process_list[i].join() end = time() print("多进程运行时间:", end - start) print("多进程结束:".center(30, "*")) if __name__ == "__main__": main()