多线程
多线程
1线程理论知识
- 什么是线程
- 线程就是一条流水线
- 进程 : 划分空间,加载资源,静态的.
- 线程 : 执行代码,执行能力,动态的
- 线程VS进程
- 开启多进程开销非常大,开启线程开销非常小
- 开启多进程的速度慢,开启多线程速度快
- 进程之间数据不能直接共享,通过队列可以,同一进程下的线程之间的数据可以共享
- 多线程的应用场景介绍
- 并发:一个cpu来回切换,多进程并发,多线程的并发
- 多进程并发:开启多个进程,每个进程里面的主线程执行任务
- 多线程并发:开启一个进程,进程里面的多个线程执行任务
2.开启线程的两种方式
-
第一种方式
-
# 第一种方式 # from threading import Thread # # def task(name): # print(f'{name} is running') # # if __name__ == '__main__': # t = Thread(target=task,args=('mcsaoQ',)) # t.start() # # print('主线程')
-
-
第二种方式
-
from threading import Thread class MyThread(Thread): def run(self): print(f'{self.name} is running') if __name__ == '__main__': t = MyThread() t.start() print('主线程')
-
3.线程与进程之间的对比
-
速度的对比
-
from threading import Thread def task(name): print(f'{name} is running') if __name__ == '__main__': t = Thread(target=task,args=('mcsaoQ',)) t.start() print('主线程') ''' 线程绝对要比进程要快: mcsaoQ is running 主线程 '''
-
-
pid
-
# pid 进程号 from threading import Thread import os def task(): print(f'子线程: {os.getpid()}') if __name__ == '__main__': t = Thread(target=task,) t.start() print(f'主线程: {os.getpid()}')
-
-
线程之间的共享资源
-
# from threading import Thread # # x = 1000 # # def task(): # global x # x = 0 # # # if __name__ == '__main__': # t = Thread(target=task) # t.start() # # t.join() # print(f'主线程: {x}') # from threading import Thread # import time # x = 1000 # # def task(): # time.sleep(3) # print('子线程....') # # # def main(): # print('111') # print('222') # print('333') # # # # # task() # # main() # # if __name__ == '__main__': # t = Thread(target=task) # t.start() # # t.join() # main()
-
4.线程的其他方法
-
# from threading import Thread # import threading # import time # # # def task(name): # time.sleep(1) # print(f'{name} is running') # print(threading.current_thread().name) # # # # if __name__ == '__main__': # for i in range(5): # t = Thread(target=task,args=('mcsaoQ',)) # t.start() # # 线程对象的方法: # # time.sleep(1) # # print(t.is_alive()) # 判断子线程是否存活 *** # # print(t.getName()) # 获取线程名 # # t.setName('线程111') # # print(t.getName()) # 获取线程名 # # # threading模块的方法: # # print(threading.current_thread().name) # MainThread # # print(threading.enumerate()) # 返回一个列表 放置的是所有的线程对象 # print(threading.active_count()) # 获取活跃的线程的数量(包括主线程) # print('主线程')
5.守护线程
-
守护:子线程守护主线程,
-
结束条件:守护线程必须等待主线程结束才结束,主线程必须等所有的非守护线程结束才能结束
-
from threading import Thread import time def foo(): print(123) time.sleep(3) print("end123") def bar(): print(456) time.sleep(1) print("end456") if __name__ == '__main__': t1=Thread(target=foo) t2=Thread(target=bar) t1.daemon = True t1.start() t2.start() print("main-------")
6.互斥锁(同步锁)
7.死锁现象,递归锁
-
进程由死锁与递归锁,与线程同理,
-
死锁: 是指两个或两个以上的进程或线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去,此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程,如下就是死锁
-
from threading import Thread from threading import Lock import time lock_A = Lock() lock_B = Lock() class MyThread(Thread): def run(self): self.f1() self.f2() def f1(self): lock_A.acquire() print(f'{self.name}拿到A锁') lock_B.acquire() print(f'{self.name}拿到B锁') lock_B.release() lock_A.release() def f2(self): lock_B.acquire() print(f'{self.name}拿到B锁') time.sleep(0.1) lock_A.acquire() print(f'{self.name}拿到A锁') lock_A.release() lock_B.release() if __name__ == '__main__': for i in range(3): t = MyThread() t.start() print('主....')
-
-
解决死锁的方法:递归锁,在python中为了支持同一线程中多次请求同一资源,Python提供了可重入锁RLock
-
RLock内部维护着一个Lock和counter变量,counter记录了acquire的次数,从而使得资源可以被多次require,直到一个线程所有的acquire都被release,其他线程才能获取资源,上面的例子如果使用RLock代替Lock,则不会发生死锁:
-
from threading import Thread from threading import RLock import time lock_A = lock_B = RLock() class MyThread(Thread): def run(self): self.f1() self.f2() def f1(self): lock_A.acquire() print(f'{self.name}拿到A锁') lock_B.acquire() print(f'{self.name}拿到B锁') lock_B.release() lock_A.release() def f2(self): lock_B.acquire() print(f'{self.name}拿到B锁') time.sleep(0.1) lock_A.acquire() print(f'{self.name}拿到A锁') lock_A.release() lock_B.release() if __name__ == '__main__': for i in range(10): t = MyThread() t.start() print('主....')
-
8.信号量
-
Semaphore管理一个内置的计数器,每当调用acquire()时内置计数器+1,调用release()时内置计数器-1,计数器不能小于0,当计数器为0时,acquire()将阻塞线程直到其他线程调用release(),
-
from threading import Thread from threading import Semaphore from threading import current_thread import time import random sem = Semaphore(5) def go_public_wc(): sem.acquire() print(f'{current_thread().getName()} 上厕所ing') time.sleep(random.randint(1,3)) sem.release() if __name__ == '__main__': for i in range(20): t = Thread(target=go_public_wc) t.start()