快速玩转python多任务编程

1、多任务介绍

多任务就是在同一时间同时运行多个任务,比如在跳舞的时候唱歌,在看书的时候听歌,电脑在运行微信时,也在运行QQ,word等软件,这些都是多任务的应用,多任务可以提高执行效率,充分利用CPU资源,让程序具备处理多个任务的能力。
执行方式:

  • 并行
  • 并发

并发:在一段时间内,交替执行任务
并发针对单核cpu,存在竞争关系,都在争夺cpu资源,严格来说并不是真正意义的多任务执行,只是间隔时间很短,我们肉眼不能区分,看上去像同时在执行一样
例如:
只有1位辅导老师,学生都想让老师为自己辅导,每位学生之间存在竞争关系,老师每次只能为1位学生辅导,因此对老师来说就是并发执行辅导学生的任务,辅导完甲同学,再去辅导乙同学,接着再去辅导丙同学。
在这里插入图片描述

并行:同一时间,同时执行多个任务
针对多核CPU,操作系统会给每个内核分配一个任务,属于真正的一起执行任务,多核cpu是并行执行多任务,始终有多个任务同时执行。
注意:

  • 只有多核CPU才能真正意义上让多个软件一起运行
  • 任务数小于cpu核数,并行方式运行
  • 任务数大于cpu核数,并发方式运行
    在这里插入图片描述

实现多任务的方式:

  • 进程
  • 线程
  • 协程

2、进程

2.1进程介绍

进程顾名思义“进行当中的程序”,因此进程必须是正在运行当中,如果没有运行就不能叫做进程,只能叫程序。只要程序开始运行,即进程启动,操作系统就会分配内存资源,因此进程是操作系统进行资源分配的基本单位
进程只负责向操作系统索要内存资源,而实际执行任务的是线程,启动1个程序,至少有1个进程,1个进程默认有1个线程,线程依附于进程,没有进程就没有线程
例如:
进程可以任务就是一个公司,线程是员工,真正干活的是员工,公司只为员工提供办公场地,没有公司也就没有员工

2.2多进程的使用

进程之间不共享全局变量,创建子进程会对主进程资源进行拷贝,子进程是主进程的一个副本,就像是一对双胞胎,之所以进程之间不共享全局变量,是因为操作的不是同一个进程里面的全局变量,只不过不同进程里面的全局变量名字相同而已
process中有2中传参方式:

  • args:按照元组方式传参数
    注意:必须和参数的顺序相对应
  • kwargs:按照字典方式传参数
    -注意:字典的key要和参数保持想对应
# 导入进程包
import multiprocessing
import time
import os

def dance(i):
    # 获取当前进程的编号
    print("当前dance进程的编号是:",os.getpid())
    # 获取当前进程的父进程id
    print("当前dance进程的父进程编号是:",os.getppid())
    # 获取dance进程
    print("dance:",multiprocessing.current_process())
    for i in range(i):
        print("我在跳舞中")
        time.sleep(0.2)

def sing(count):
    # 获取当前进程的编号
    print("当前sing进程的编号是:",os.getpid())
    # 获取当前进程的父进程id
    print("当前sing进程的父进程编号是:",os.getppid())
    # 获取sing进程
    print("sing:",multiprocessing.current_process())
    for i in range(count):
        print("我在唱歌中")
        time.sleep(0.2)

if __name__ == '__main__':
    # 获取当前主进程的编号:
    print("当前main进程的编号:",os.getpid())
    # 获取主进程
    print("main:",multiprocessing.current_process())
    # target:执行的目标任务名,name:进程名字
    dance_process = multiprocessing.Process(target=dance,name="myprocess1",args=(2,))
    sing_process = multiprocessing.Process(target=sing,name="myprocess2",kwargs={"count":2})

    # 启动子进程实例(创建子进程)
    dance_process.start()
    sing_process.start()

运行结果:

当前main进程的编号: 17816
main: <_MainProcess(MainProcess, started)>
当前dance进程的编号是: 3404
当前sing进程的编号是: 19308
当前dance进程的父进程编号是: 17816
dance: <Process(myprocess1, started)>
我在跳舞中
当前sing进程的父进程编号是: 17816
sing: <Process(myprocess2, started)>
我在唱歌中
我在跳舞中
我在唱歌中

Process finished with exit code 0

3、线程和互斥锁

明白了进程,再说线程就简单很多了,线程就是真正做事的人,每个线程需要cpu调度才能执行任务,因此说,线程是cpu调度的基本单位,每个进程至少有一个线程,这个线程就是我们经常说的主线程
线程之间可以进行全局变量共享,为了保证数据准确,引入互斥锁概念
互斥锁:对共享数据进行锁定,使同一时间只能有1个线程使用,多个线程去抢这把锁,谁抢到就是谁使用,其他未抢到锁的线程,处于继续等待状态,待锁释放后继续重新抢

# 导入进程包
import threading
import time

# 创建锁
mutex = threading.Lock()

def study():
    # 上锁
    mutex.acquire()
    # 获取当前线程
    print("当前的study线程是:",threading.current_thread())
    for i in range(3):
        print("学习中。。。")
        time.sleep(0.2)
    # 释放锁
    mutex.release()

def play():
    # 上锁
    mutex.acquire()
    # 获取当前线程
    print("当前的play线程是:",threading.current_thread())
    for i in range(3):
        print("玩耍。。。")
        time.sleep(0.2)
    # 释放锁
    mutex.release()

if __name__ == '__main__':
    study_thread = threading.Thread(target=study)
    play_thread = threading.Thread(target=play)
    # 启动线程
    study_thread.start()
    play_thread.start()

运行结果:

当前的study线程是: <Thread(Thread-1, started 5136)>
学习中。。。
当前的play线程是: <Thread(Thread-2, started 4544)>
玩耍。。。
玩耍。。。
学习中。。。
玩耍。。。
学习中。。。

Process finished with exit code 0

注意:
上锁之后应在适当的地方释放锁,不然容易造成死锁,导致程序卡死,崩溃,如下面这段代码:

import threading
import time

# 创建互斥锁
lock = threading.Lock()

# 根据下标去取值, 保证同一时刻只能有一个线程去取值
def value(index):
    # 上锁
    lock.acquire()
    print(threading.current_thread())
    mylist = [3,4,12]
    # 判断下标释放越界
    if index >= len(mylist):
        print("下标越界:", index)
        # 未释放锁,直接返回,导致线程卡死
        return
    value = mylist[index]
    print(value)
    time.sleep(0.2)
    # 释放锁
    lock.release()


if __name__ == '__main__':
    # 模拟大量线程去执行取值操作
    for i in range(30):
       index_thread = threading.Thread(target=value, args=(i,))
       index_thread.start()

执行结果:
卡死,无法正常退出

Thread(Thread-1, started 14876)>
3
<Thread(Thread-2, started 13652)>
4
<Thread(Thread-3, started 16336)>
12
<Thread(Thread-4, started 16512)>
下标越界: 3
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值