【0917 | Day 32】线程/线程join/线程和进程区别/线程方法/守护线程
线程介绍
简单介绍
操作系统 ===> 工厂
进程 ===> 车间
线程 ===> 流水线
CPU ===> 电源
线程:CPU最小的执行单位
进程:资源集合/资源单位
线程运行 = 运行代码
进程运行 = 各种资源 + 线程
在传统的操作系统中,每次开启进程,则会开辟出一块内存空间,默认控制一个线程,CPU执行线程。
右键运行
申请内存空间,依次丢进解释器(解释器的作用是解释代码)和代码,执行代码(线程)
进程和线程区别
区别一:过程描述的区别
线程==》单指代码的执行过程
进程==》资源的申请与销毁的过程
区别二:资源共享的区别
进程的内存空间彼此隔离
from multiprocessing import Process
import time
x = 0
def task():
global x
x = 100
print('子进程的x修改为了{}'.format(x))
if __name__ == '__main__':
p = Process(target=task)
p.start()
time.sleep(5)
print(x)
#子进程的x修改为了100
#0
同进程下的线程共享资源
#子线程
from threading import Thread
import time, os
x = 100
def task():
global x
x = 50
print(os.getpid()) # 5204
if __name__ == '__main__':
t = Thread(target=task)
t.start()
time.sleep(2)
print(x) # 50
print(os.getpid()) # 5204
区别三:创建速度的区别
进程需要申请资源开辟空间 慢
只是告诉操作系统一个执行方案 快
from threading import Thread
from multiprocessing import Process
import time
def task(name):
print(f'{name} is running')
time.sleep(2)
print(f'{name} is end')
if __name__ == '__main__':
t = Thread(target=task,args=('子线程',))
#p = Process(target=task,args=('子进程',))
t.start()
#p.start()
print('主')
#开启子线程的打印效果:
子线程 is running
主
子线程 is end
#开启子进程打印效果:
主
子进程 is running
子进程 is end
线程开启的两种方式
方式一
from threading import Thread
import time
def task():
print('线程 start')
time.sleep(2)
print('线程 end')
if __name__ == '__main__':
t = Thread(target=task)
t.start() # 告诉操作系统开一个线程 .
print('主')
方式二
from threading import Thread
import time
# 进程等待所有线程结束才会结束
class Myt(Thread):
def run(self):
print('子线程 start')
time.sleep(5)
print('子线程 end')
#不需要if __name__ == '__main__':
t = Myt()
t.start()
print('主线程')
线程的join方法
等待子线程运行结束
不加join( )
from threading import Thread
import time
def task():
print('子线程 start')
time.sleep(2)
print('子线程 end')
t = Thread(target=task)
t.start()
print('主线程')
子线程 start
主线程
子线程 end
第一种:加join( )
等待子线程运行结束
from threading import Thread
import time
def task():
print('子线程 start')
time.sleep(2)
print('子线程 end')
t = Thread(target=task)
t.start()
t.join() #等待子线程运行结束
print('主线程')
子线程 start
子线程 end
主线程
第二种:加join( )
实现并行
from threading import Thread
import time
def task(name, n):
print(f'{name} start')
time.sleep(n)
print(f'{name} end')
t1 = Thread(target=task, args=('线程1', 1))
t2 = Thread(target=task, args=('线程2', 2))
t3 = Thread(target=task, args=('线程3', 3))
start = time.time()
t1.start()
t2.start()
t3.start()
t1.join() #实现并行
t2.join() #实现并行
t3.join() #实现并行
end = time.time()
print(end-start)
线程1 start
线程2 start
线程3 start
线程1 end
线程2 end
线程3 end
3.002016305923462
思考:多线程程序在单核CPU与多核CPU上是怎么工作?
我以此说明一下,CPU的世界里:
“一个人只能杠一个木头,一堆人不能同时杠一个木头。”
多线程程序其实是把里面可拆分的逻辑或者说不同的任务交给了不同的线程去做,也就是说:
“一堆人框一堆木头”是基于多个“一个人框一个木头”实现的。
对于可拆分逻辑而言(不同的木头可以由不同的人搬),多个人可以协同工作,可以加快工作效率,但是对于不可拆分逻辑而言(比如解一元一次方程),多个人无法协同工作,再多的人,工作效率也跟一个人一样。
所以你提到的多线程程序,往往就是指里面有多个独立逻辑块的程序。
反过来,单核多线程是怎么实现的?
一个人和多个木头是怎样的关系:搬完一个再搬一个。
这就是答案,不过我们的操作系统会让单个核心尽可能地来回地在多个进程之间切换,尽可能达到多个优先级类似的程序在并行类似的效果(例:单核CPU时代我们依然可以边听歌边上网)。
换算成人和木头的关系就是一个人先把a木头搬一段,再把b木头搬一段,再把c木头搬一段,然后再去搬a木头……类似如此。
了解进程的join方法
主进程的主线程等待子进程运行结束(主线程在主线程里面)
from multiprocessing import Process
from threading import Thread
import time
def task():
print('进程 开启')
time.sleep(10)
print('进程 结束')
def task2():
print('子线程 开启')
time.sleep(2)
print('子线程 结束')
if __name__ == '__main__':
p = Process(target=task)
t = Thread(target=task2)
t.start() # 开线程
p.start() # 开进程
print('子进程join开始')
p.join() #主进程的主线程等待子进程运行结束
print('主')
子线程 开启
子进程join开始
进程 开启
子线程 结束
进程 结束
主
线程其他相关用法
from threading import Thread,currentThread,enumerate,activeCount
# import threading
import time
# threading.current_thread()
# threading.current_thread()
def task():
print('子线程 start')
time.sleep(2)
print('子线程 end')
print(enumerate())
# print(currentThread(),'子线程')
if __name__ == '__main__':
t1 = Thread(target=task)
t2 = Thread(target=task)
t1.start()
t2.start()
print(t1.is_alive()) # True
print(t1.getName()) # Thread-1
print(t2.getName()) # Thread-2
t1.setName('班长')
print(t1.getName()) # 班长
print(currentThread().name)
print(enumerate())
# [<_MainThread(MainThread, started 1856)>, <Thread(Thread-1, started 6948)>, <Thread(Thread-2, started 3128)>]
print(activeCount()) # 3
print(len(enumerate())) # 3
守护线程
守护进程的运行周期
from threading import Thread,enumerate,currentThread
import time
def task():
print('守护线程开始')
# print(currentThread())
time.sleep(20)
print('守护线程结束')
def task2():
print('子线程 start')
time.sleep(5)
# print(enumerate())
print('子线程 end')
if __name__ == '__main__':
t1 = Thread(target=task)
t2 = Thread(target=task2)
t1.daemon = True
t1.start()
t2.start()
print('主')
守护线程开始
子线程 start
主
子线程 end
注意:task2中的最后一行代码结束,守护进程task立即结束,不再执行print('守护线程结束')。