1
0
0

04-多任务编程

多任务

思维导图

python高级编程04.png

多进程

一个程序最少有一个进程,也叫做主进程,进程是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同时处理多个线程,并发)

场景:以后开发,百分之九十场景都是使用多线程。抢票(多个任务同时共享一个数据)

多协程(主要解决问题的方案)

支持与分享

如果这篇文章对你有帮助,欢迎分享给更多人或者给予支持!