多线程

mac2022-06-30  93

线程

什么是线程

程序在运行代码的过程。

进程与线程

进程:一个在运行中的程序(具体内容是由线程来运行)的状态,是系统的一个资源单位。

线程:运行指定代码的过程。一个进程中至少有一个线程,但是一个进程可以有多个线程。线程是cpu调度的最小单位。

类比到现实中就是生产车间(指代进程)与流水线(指代线程)的关系。我们可以说这个车间是生产汽车,生产车间里面的每一条流水线都是生产汽车部件的。生产车间是由一个一个流水线组合成地。进程也是由线程构成地。

线程与进程的区别

进程之间是内存隔离,线程之间是共享内存创建进程由于需要开辟内存空间,而线程不需要开辟内存空间,所以创建线程的速度比创建进程的速度快

线程创建的两种方式

使用threading模块创建Thread,而且创建线程的方式与multiprocessing创建线程的方式一样(据说是multiprocessing照着threading写的,不要说是我说的)

方式一:实现Thread类

from threading import Thread,currentThread def pr(): print(f'我是进程{currentThread().name}!') t = Thread(target=pr) t.start() print('我是主进程!') ####################### # 结果: 我是进程Thread-1! # 因为创建线程的速度很快所以创建了线程就执行了代码 我是主进程!

方式二:继承Thread类

from threading import Thread,currentThread class MyT(Thread): def run(self) -> None: # 必须重写run方法 print(f'我是进程{currentThread().name}') t = MyT() t.start() print('我是主进程!') ####################### # 结果: 我是进程Thread-1! 我是主进程!

线程的属性和方法

join

主线程等待子线程运行结束

from threading import Thread import time def task(): print('子线程开启!') time.sleep(2) print('子线程结束!') t = Thread(target=task) t.start() print('主线程结束!') ###################### # 结果: 子线程开启! 主线程结束! 子线程结束!

isAlive()

线程是否还在运行

from threading import Thread import time def task(): print('子线程开启!') time.sleep(2) print('子线程结束!') t = Thread(target=task) t.start() time.sleep(1) print(t.isAlive()) # True print('主线程结束')

getName()

获取线程名字

from threading import Thread import time def task(): print('子线程开启!') time.sleep(2) print('子线程结束!') t = Thread(target=task) t.start() print(t.getName()) # Thread-1 print('主线程结束')

setName()

设置线程名字

from threading import Thread import time def task(): print('子线程开启!') time.sleep(2) print('子线程结束!') t = Thread(target=task) t.start() print(t.getName()) # Thread-1 t.setName('张三') print(t.getName()) # 张三 print('主线程结束')

currentThread()

获取当前线程对象

from threading import Thread,currentThread import time def task(): print(currentThread().getName()) # Thread-1 currentThread().setName('张三') print(currentThread().getName()) # 张三 t = Thread(target=task) t.start() time.sleep(0.5) print(t.getName()) # 张三 print('主线程结束')

enumerate()

返回当前活动进程

from threading import Thread,enumerate import time def task(): print('子线程开启!') time.sleep(2) print('子线程结束!') t = Thread(target=task) t.start() print(enumerate()) # [<_MainThread(MainThread, started 3068)>, <Thread(Thread-1, started 16348)>] print('主线程结束')

activeCount()

返回当前活动线程数量

from threading import Thread,activeCount import time def task(): print('子线程开启!') time.sleep(2) print('子线程结束!') t = Thread(target=task) t.start() print(activeCount()) # 2 print('主线程结束')

守护线程

守护线程守护至当前进程结束

from threading import Thread import time def task(): print('子线程开启!') time.sleep(2) print('子线程结束!') t = Thread(target=task) t.daemon = True t.start() print('主线程结束')

但是,主进程会等待还没有结束的子线程结束后结束

from threading import Thread import time def task(): print('守护线程开启!') time.sleep(2) print('守护线程结束!') def pr(): print('子线程开启!') time.sleep(3) print('子线程结束!') t = Thread(target=task) t.daemon = True t.start() t = Thread(target=pr) t.start() print('主线程结束')

线程锁

当我们要对线程间共享的资源进行操作,为了资源的安全考虑,就需要为资源加上线程锁。这样就可以保证同一个资源同一时刻只有一个线程有权限去修改。

from threading import Lock,Thread import time #初始化一把锁,由于线程间共享内存所以可以不用传递参数 lock=Lock() count = 1 def buy(): #获取钥匙在acquire()和release()之间的代码在同一时间只允许一个进程执行,当一个进程完成后将钥匙归还后,其他的进程才可以获得钥匙。 lock.acquire() # 拿锁 # 模拟网络的延迟 global count time.sleep(0.1) if count>0: print('买到票了') count=count-1 with open('access.txt', 'w', encoding='utf-8') as f: f.write(str(count)) else: print('没票了') lock.release() #还锁 count = 1 for i in range(5): p=Thread(target=buy) p.start()

死锁

当程序中有两把锁,并且一个线程需要拿到两把锁才能运行下去的时候,就会发生死锁的问题

from threading import Lock,Thread,currentThread import time lock1 = Lock() lock2 = Lock() def func1(): lock2.acquire() print('\033[41m%s 拿到A锁\033[0m' % currentThread().name) lock1.acquire() print('\033[42m%s 拿到B锁\033[0m' % currentThread().name) lock1.release() lock2.release() def func2(): lock1.acquire() print('\033[43m%s 拿到B锁\033[0m' % currentThread().name) time.sleep(2) lock2.acquire() print('\033[44m%s 拿到A锁\033[0m' % currentThread().name) lock2.release() lock1.release() t1 = Thread(target=func2) t2 = Thread(target=func1) t1.start() t2.start()

解决死锁问题可以使用 递归锁

递归锁

在一个线程中是的锁可以被多次获取,但是不同线程间只能有一个线程获得锁

from threading import RLock,Thread,currentThread import time lock1 = RLock() lock2 = lock1 def func1(): lock2.acquire() print('\033[41m%s 拿到A锁\033[0m' % currentThread().name) lock1.acquire() print('\033[42m%s 拿到B锁\033[0m' % currentThread().name) lock1.release() lock2.release() def func2(): lock1.acquire() print('\033[43m%s 拿到B锁\033[0m' % currentThread().name) time.sleep(2) lock2.acquire() print('\033[44m%s 拿到A锁\033[0m' % currentThread().name) lock2.release() lock1.release() t1 = Thread(target=func2) t2 = Thread(target=func1) t1.start() t2.start()

GIL(全局解释器锁)

因为cpython自带的垃圾回收机制不是线程安全的,所以要有GIL锁来保证同一时间只有一个线程在解释器中运行。但是这会导致cpython中的多线程并不是真正意义上的多线程,它只能运用到单核的性能。

解决这个问题主要有两种办法:

使用多线程使用C语言写多线程的部分,再使用ctypes模块

具体可以看:https://blog.csdn.net/IAlexanderI/article/details/72932309

线程间通信

队列

先进先出

import queue q = queue.Queue() q.put('123') q.put('qweqwe') print(q.get()) print(q.get()) ############### # 结果: 123 qweqwe

后进先出

import queue q = queue.LifoQueue() q.put('123') q.put('qwe') q.put('asd') print(q.get()) print(q.get()) print(q.get()) ################ # 结果: asd qwe 123

优先级

按照元组中的优先级输出

import queue q = queue.PriorityQueue() q.put((4,'123')) q.put((2,'qwe')) q.put((3,'asd')) print(q.get()) print(q.get()) print(q.get()) ################ # 结果: (2, 'qwe') (3, 'asd') (4, '123')

线程定时器

倒计时,当时间归零开始执行线程

from threading import Timer def task(): print('线程开始执行') t = Timer(4,task) # 过了4s后开启了一个线程 t.start()

转载于:https://www.cnblogs.com/Gredae/p/11570308.html

最新回复(0)