线程
线程是需要依赖于进程的,它有独立的资源,进程内有一个相对独立的,可调度的执行单元,是进程中的实际运作单位
线程的优点:
1.使用线程可以把占据长时间的程序中的任务放到后台去处理。
2.用户界面可以更加吸引人,这样比如用户点击了一个按钮去触发某些事件的处理,可以弹出一个进度条来显示处理的进度。
3.程序的运行速度可能加快。
4.在一些等待的任务实现上如用户输入,文件读写和网络收发数据等,线程就比较有用了。在这种情况下,我们可以释放一些珍贵的资源,如内存占用等。
创建线程:
导入threading,使用其中的Thread类
import threading
# target 函数 name 线程名 args 传参
t1 = threading.Thread(target=func, name='AA', args=(1,))
t.start()
t.join()
锁
在使用多线程时,为了保证数据的正确性,避免存在数据不同步的问题,所以引入了锁的概念
GIL:全局解释器锁
运算率达到一定的时候就会自动释放
python底层只要用线程就会默认加锁GIL
创建一个锁对象:
import threading
lock = threading.Lock()
请求得到锁
lock.acquire()
释放锁
lock.release()
死锁:先有锁a,b,线程(进程)a,b
线程t1首先使用锁a 然后休眠,此时锁a被使用 未释放
线程t1休眠时,线程t2使用锁b 然后休眠,此时锁b被使用 未释放
线程t1休眠结束,继续运行,占用资源、申请锁b,同时锁b被线程t2使用,是阻塞状态 无法释放,而线程t1则一直占用资源等待锁b释放,线程t2占用锁b却因为资源被占用无法释放锁b
此时就是死锁状态,会造成应用的停止响应,程序不做任何事情
要避免造成死锁的情况
会造成死锁的代码:
from threading import Thread,Lock
import time
lockA = Lock()
lockB = Lock()
class Mythread1(Thread):
def run(self):
if lockA.acquire():
print(self.name+'获取了A锁')
time.sleep(0.1)
if lockB.acquire():
print(self.name+'获取了A锁之后又获取了B锁')
lockA.release()
class Mythread2(Thread):
def run(self):
if lockB.acquire():
print(self.name+'获取了B锁')
time.sleep(0.1)
if lockA.acquire():
print(self.name+'获取了B锁之后又获取了A锁')
lockA.release()
lockB.release()
if __name__ == '__main__':
t1 = Mythread1()
t2 = Mythread2()
t1.start()
t2.start()