1
0
0
04-多任务编程
多任务
思维导图

多进程
一个程序最少有一个进程,也叫做主进程,进程是CPU分配资源的最小单位,进程之间的内存是隔离的,子进程创建的时候会复制主进程的全局变量,不会共享
进程:正在进行的程序
守护进程:
l1 = []
def eat(food):
#拷贝一份l1
for i in range(10):
print(f'吃东西{food}')
l1.append(1)
time.sleep(0.5)
def drink(juice):
#拷贝一份l1
for i in range(10):
print(f'喝东西{juice}')
l1.append(2)
time.sleep(0.5)
if __name__ == '__main__':
#耗时10秒
# eat() #5s
# drink() #5s
#耗时5s
1.创建进程对象
p1 = multiprocessing.Process(target=eat,args=('榴莲',),group=没有作用,name='进程1',daemen=True)
p2 = multiprocessing.Process(target=eat,kwargs={"juice":"威士忌"},name='进程2')
2.使用进程对象开启进程
p1.start() #子进程是通过主进程开启的
p2.start() #子进程是通过主进程开启的
#手动结束进程
p1.terminate()
p2.terminate()
进程可以单个守护,因为进程可以单个关闭
拓展:进程之间不能共享全局变量,但可以共享数据
多线程
一个进程至少得有一个线程,也叫主线程
线程是CPU调度的最小单位
创建线程对象
开启线程
线程传参
线程数据共享(互斥锁)
守护线程
l1 = []
def eat(food):
#可以共享全局变量(会有问题)
for i in range(10):
print(f'吃东西{food}')
l1.append(1)
time.sleep(0.5)
def drink(juice):
#可以共享全局变量(会有问题)
for i in range(10):
print(f'喝东西{juice}')
l1.append(2)
time.sleep(0.5)
if __name__ == '__main__':
#耗时10秒
# eat() #5s
# drink() #5s
#耗时5s
1.创建进程对象
p1 = threading.Tread(target=eat,args=('榴莲',),group=没有作用,name='进程1',daemen=True)
p2 = multiprocessing.Process(target=eat,kwargs={"juice":"威士忌"},name='进程2',daemen=True)
2.使用进程对象开启进程
p1.start() #子进程是通过主进程开启的
p2.start() #子进程是通过主进程开启的
线程的守护是要守护就全守护,只有一个守护没有用,因为线程没法单独关闭
线程共享全局变量可以能会导致数据异常,解决方案是使用互斥锁
import threading
import time
# 票
num = 3
def fn(lock):
# 上锁 - lock.locked
# lock.acquire()
with lock:
global num
if num >0:
# 抢了一张票
time.sleep(0.5) #模拟支付的时间
num -= 1
print(f"{threading.current_thread().name}抢了一张票,剩余票数:{num}",)
# 解锁
# lock.release()
if __name__ == '__main__':
# 锁 - 一把锁
lock = threading.Lock()
# lock.acquire() 上锁
# lock.release() 解锁
t1 = threading.Thread(target=fn,name="线程1",args=(lock,))
t2 = threading.Thread(target=fn,name="线程2",args=(lock,))
t3 = threading.Thread(target=fn,name="线程3",args=(lock,))
t4 = threading.Thread(target=fn,name="线程4",args=(lock,))
t5 = threading.Thread(target=fn,name="线程5",args=(lock,))
t1.start()
t2.start()
t3.start()
t4.start()
t5.start()
# 等待线程/进程执行
t1.join()
t2.join()
t3.join()
t4.join()
t5.join()
print(f"抢票结束:还有{num}张票")
# 1.线程之间可以共享全局变量,但是同时修改全局变量会出现问题
# 2.解决线程之间共享数据的问题可以使用互斥锁,进行确保数据修改的安全问题
# 创建锁:lock = threading.Lock()
# 把锁传递给线程:threading.Thread(target=fn,name="线程2",args=(lock,))
# 线程修改数据的地方上锁: with lock:
# 上锁会保证数据的安全性,同时也会降低代码的执行效率!
线程与进程的区别(GIL)
场景:CPU就是员工,进程就是员工要处理的任务,线程就是员工处理任务的分支
进程 - CPU分配资源的最小单位 - 多个CPU就可以同时处理多个进程(CPU足够多的情况下,并行)
进程可以独立关闭,适合使用守护进程的场景(王者荣耀:游戏结束,画面+音频需要同时结束)
假设把任务(进程)A分配给了张三,此时GIL就会悄悄进行内部锁定(确保其他的CPU不能动这个任务)
线程 - CPU调度的最小单位 - 多个CPU即使有空闲,因为进程被1个CPU锁定,导致其他CPU不能进行支援(1个CPU同时处理多个线程,并发)
场景:以后开发,百分之九十场景都是使用多线程。抢票(多个任务同时共享一个数据)
