1.线程的理论知识
-
什么是线程
线程就是一条流水线.
什么是进程? 进程开启经历了什么?
开启进程: 内存中开空间,加载资源与数据,调用cpu执行,可能还会使用这个空间的资源.
进程: 主要任务:,开启空间,加载数据.
线程: 流水线,执行代码.
进程: 划分空间,加载资源. 静态的.
线程: 执行代码.执行能力,动态的.
抽象的概念.
开启qq: 开启一个进程: 在内存中,开空间,加载数据. 启动一个线程执行代码.
线程是依赖于进程, 一个进程可以包含多个线程.但是一定有一个主线程. 线程才是cpu执行的最小单元.
-
线程vs进程(理论)
-
开启多进程开销非常大. 10~100.开启线程开销非常小.
-
开启多进程的速度慢,开启多线程速度快.
-
进程之间数据不能直接共享通过队列可以.同一个进程下的线程之间的数据可以共享.
-
-
多线程的应用场景介绍
并发: 一个cpu来回切换(线程之间的切换). 多进程并发, 多线程的并发.
多进程并发: 开启多个进程, 每个进程里面的主线程执行任务.
多线程并发: 开启1个进程, 此进程里面多个线程执行任务.
什么时候用多进程,什么时候用多线程?
一个程序: 三个不同的任务.
如果以后工作中遇到并发:多线程居多.
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 import time x = 1000 def task(): time.sleep(3) print('子线程....') def main(): print('111') print('222') print('333') 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.互斥锁(锁)
互斥锁,锁,同步锁都是一把锁.
互斥锁与join区别?
互斥锁 随机抢锁,公平. join 提前排好顺序,不公平.但是都是串行.
7.死锁现象,递归锁
递归锁: 递归锁是一把锁,锁上有记录,只要acquire一次,锁上就计数1次, acquire2次,锁上就计数2次,release1次,减一, 只要递归锁计数不为0,其他线程不能抢.
from threading import Thread
from threading import Lock
from threading import RLock
import time
# lock_A = RLock()
# lock_B = RLock()
lock_A = lock_B = RLock()
class MyThread(Thread):
def run(self):
# lock_A.acquire()
# lock_B.acquire()
# print(111)
# lock_A.release()
# lock_B.release()
self.f1()
self.f2()
def f1(self):
lock_A.acquire()
print(f'{self.name}拿到 A锁')
lock_B.acquire() # 第二个线程抢B锁
print(f'{self.name}拿到 B锁')
lock_B.release()
lock_A.release()
def f2(self):
lock_B.acquire()
print(f'{self.name}拿到 B锁')
time.sleep(1) # 第一个线程 睡1秒
lock_A.acquire() # 第一个线程抢A锁
print(f'{self.name}拿到 A锁')
lock_A.release()
lock_B.release()
if __name__ == '__main__':
# for i in range(3):
# t = MyThread()
# t.start()
t1 = MyThread()
t1.start()
t2 = MyThread()
t2.start()
t3 = MyThread()
t3.start()
print('主线程')
8.信号量
之前讲的锁都是只允许一个线程或者进程进入.信号量允许多个线程或者进程同时进入
from threading import Thread
from threading import current_thread
from threading import Semaphore
import time
import random
sm = Semaphore(4)
# lock= Lock()
def go_public_wc():
sm.acquire()
print(f'{current_thread().name}正在厕所')
time.sleep(random.randint(1, 3))
sm.release()
if __name__ == '__main__':
for i in range(20):
t = Thread(target=go_public_wc)
t.start()
# print('主')