点我

多任务

多任务指的是同一时间内执行多个任务

多任务有两种表现形式:

  • 并发
  • 并行

并发:在一段时间内交替去执行多个任务

并行:在一段时间内真正的同时一起执行多个任务

多任务的作用:充分利用CPU的资源,提高程序执行效率

进程

概述

进程(Process)是资源分配的最小单元,它是操作系统进行资源分配和调度运行的基本单元

通俗理解:一个正在运行的程序就是一个进程

进程的作用

可以使用多进程的方式去完成多任务

进程创建步骤

1、导入进程包

import multiprocessing

2、通过进程类创建进程对象

进程对象 = multiprocessing.Process(target=任务名[,name=进程名,group=进程组,目前只能使用None])

3、启动进程执行任务

进程对象.start()

代码部分--单任务

"""
@time:2022-03-29
@desc:
    进程的单任务
    分别执行唱歌和跳舞
"""
import time


# 唱歌
def sing():
    for i in range(3):
        print("唱歌...")
        time.sleep(0.5)


# 跳舞
def dance():
    for i in range(3):
        print("跳舞...")
        time.sleep(0.5)


if __name__ == "__main__":
    sing()
    dance()

结果输出:

img

代码部分--多进程实现多任务

"""
@time:2022-03-29
@desc:
    同时执行唱歌,跳舞

    多进程三步骤:
        1、导入进程包
        2、使用进程类创建进程对象
        3、进程对象启动进程执行指定的任务
"""
import time
# 导入进程包
import multiprocessing

# 唱歌
def sing():
    for i in range(3):
        print("唱歌...")
        time.sleep(0.5)


# 跳舞
def dance():
    for i in range(3):
        print("跳舞...")
        time.sleep(0.5)


if __name__ == '__main__':
    # 使用进程类创建创建进程对象
    sing_process = multiprocessing.Process(target=sing)
    dance_process = multiprocessing.Process(target=dance)

    # 使用进程对象启动进程执行指定任务
    sing_process.start()
    dance_process.start()

结果输出:

img

进程执行带有参数的任务

参数名说明
args以元组的方式给执行任务传参
kwargs以字典方式给执行任务传参

代码部分

"""
@time:2022-03-29
@desc:
    
"""
import time
# 导入进程包
import multiprocessing

# 唱歌
def sing(num):
    for i in range(num):
        print("唱歌...")
        time.sleep(0.5)


# 跳舞
def dance(num):
    for i in range(num):
        print("跳舞...")
        time.sleep(0.5)


if __name__ == '__main__':
    # 使用进程类创建创建进程对象
    # args=(5,) 中的5会传递给sing(num)中的num
    sing_process = multiprocessing.Process(target=sing, args=(3,))
    # kwargs={"num": 5} 中的5会传递给dance(num)中的num
    dance_process = multiprocessing.Process(target=dance,kwargs={"num": 2})

    # 使用进程对象启动进程执行指定任务
    sing_process.start()
    dance_process.start()

结果输出:

img

获取进程的编号

进程编号的作用

当程序中的进程数量越来越多时,如果没有办法区分主进程和子进程还有不同的子进程,那么就无法进行有效的进程管理,为了方便管理实际上每个进程都是有自己的编号

获取进程编号的两种方法

  • 获取当前进程编号

os.getpid()

  • 获取当前父进程编号

os.getppid()

代码部分

"""
@time:2022-03-29
@desc:
    获取进程编号
"""
import time
import multiprocessing
import os


# 唱歌
def sing():
    print("sing父进程:", os.getppid())
    print("唱歌进程PID:", os.getpid())
    for i in range(3):
        print("唱歌...")
        time.sleep(0.5)


# 跳舞
def dance():
    print("dance父进程:", os.getppid())
    print("跳舞进程PID:", os.getpid())
    for i in range(3):
        print("跳舞...")
        time.sleep(0.5)


if __name__ == '__main__':
    # 使用进程类创建创建进程对象
    sing_process = multiprocessing.Process(target=sing)
    dance_process = multiprocessing.Process(target=dance)

    # 使用进程对象启动进程执行指定任务
    sing_process.start()
    dance_process.start()

结果输出:

img

注意事项

1、默认情况下,主进程会等待所有的子进程执行结束再结束

代码部分

"""
@time:2022-03-29
@desc:
    主进程会等待所有的子进程执行结束再结束
"""
import time
import multiprocessing


# 工作子进程
def work():
    for i in range(10):
        print("子进程工作中...")
        time.sleep(0.5)


if __name__ == '__main__':
    work_processing = multiprocessing.Process(target=work)
    work_processing.start()

    # 主进程
    time.sleep(1)
    print("主进程执行完成!")

结果输出:

img

2、设置守护主进程

为了保证子进程能够正常的运行,主进程会等待所有的子进程执行结束之后再销毁,设置守护进程的目的是主进程退出子进程销毁,不让主进程再等待子进程去执行

简而言之,守护主进程结束, 子进程不再执行剩余的代码

设置守护主进程的方式:子进程对象.daemon=True

代码部分

"""
@time:2022-03-29
@desc:
    守护主进程:主进程结束,则不再执行子进程
"""
import time
import multiprocessing


# 工作子进程
def work():
    for i in range(10):
        print("子进程工作中...")
        time.sleep(0.5)


if __name__ == '__main__':
    work_processing = multiprocessing.Process(target=work)
    # 设置守护主进程,主进程退出后子进程直接销毁,不再执行子进程中剩余的代码
    work_processing.daemon = True

    work_processing.start()

    # 主进程
    time.sleep(1)
    print("主进程执行完成!")

结果输出:

img

案例

代码部分

import os
import multiprocessing
def copy_file(file_name, source_dir, dest_dir):
    # 1 拼接源文件路径和目标文件路径
    source_path = source_dir + '\\' + file_name
    dest_path = dest_dir + '\\' + file_name
    # 2 打开源文件和目标文件
    with open(source_path, 'rb') as source_file:
        with open(dest_path, 'wb') as dest_file:
            # 3 循环读取源文件到目标路径
            while True:
                data = source_file.read(1024)
                if data:
                    dest_file.write(data)
                else:
                    break
if __name__ == '__main__':
    # 1 定义源文件夹和目标文件夹
    source_dir = r'F:\迅雷下载\视频-智能机器人从0到1系统入门课程\视频'
    dest_dir= r'F:\目标文件夹'

    # 2.创建目标文件夹
    try:
        os.mkdir(dest_dir)
    except:
        print("目标文件夹已经存在")
    # 3.读取源文件夹的文件列表
    file_list = os.listdir(source_dir)
    # 4.遍历文件列表实现拷贝
    for file_name in file_list:
        # copy_file(file_name, source_dir, dest_dir)
        # 5.使用多进程实现多任务拷贝
        sub_process = multiprocessing.Process(target=copy_file, args=(file_name, source_dir, dest_dir))
        sub_process.start()

线程

概述

进程是分配资源的最小单元,一旦创建了进程就会分配一定的资源

线程是程序执行的最小单元,实际上进程只负责分配资源,而利用这些资源执行程序的是线程

也就是说,进程是线程的容器,一个进程中最少有一个线程来负责执行程序,同时线程自己不拥有系统资源,只需要一点在运行中必不可少的资源,但它可与同属一个进程的其他线程共享进程所拥有的全部资源

多线程作用

提高效率

线程的创建步骤

1、导入线程模块

import threading

2、通过线程类创建线程对象

线程对象 = threading.Thread(target=函数名[,name = 线程名,group=线程组,目前只能使用None])

3、启动线程执行任务

线程对象.start()

代码部分--单任务

"""
@time:2022-03-29
@desc:
    单任务
"""
import time

# 唱歌
def sing():
    for i in range(5):
        print("唱歌...")
        time.sleep(0.5)


# 跳舞
def dance():
    for i in range(5):
        print("跳舞...")
        time.sleep(0.5)


if __name__ == '__main__':
    sing()
    dance()

结果输出:
img

代码部分--多任务

"""
@time:2022-03-29
@desc:
    多线程实现多任务
"""
import time
import threading

# 唱歌
def sing():
    for i in range(5):
        print("唱歌...")
        time.sleep(0.5)


# 跳舞
def dance():
    for i in range(5):
        print("跳舞...")
        time.sleep(0.5)

if __name__ == '__main__':
    # 创建线程对象
    sing_thread = threading.Thread(target=sing)
    dance_thread = threading.Thread(target=dance)

    # 启动线程
    sing_thread.start()
    dance_thread.start()

结果输出:

img

执行带有参数的任务

参数说明

参数名说明
args以元祖的形式给执行任务传参
kwargs以字典的形式给执行任务传参

代码部分

"""
@time:2022-03-29
@desc:
    带有传参的任务
"""
import time
import threading


# 唱歌
def sing(num):
    for i in range(num):
        print("唱歌...")
        time.sleep(0.5)


# 跳舞
def dance(num):
    for i in range(num):
        print("跳舞...")
        time.sleep(0.5)


if __name__ == '__main__':
    # 创建线程对象
    # 以元祖的方式传参
    sing_thread = threading.Thread(target=sing, args=(3,))
    # 以字典的方式传参
    dance_thread = threading.Thread(target=dance, kwargs={"num": 4})

    # 启动线程
    sing_thread.start()
    dance_thread.start()

结果输出:

img

主线程与子线程的结束顺序

1、默认情况下,主线程会等待所有的子线程执行结束之后主线程再结束

代码部分

"""
@time:2022-03-29
@desc:
    主线程与子线程的结束顺序
        主线程会等待所有的子线程执行结束再结束
"""
import time
import threading


# word函数
def work():
    for i in range(5):
        print("工作中...")
        time.sleep(0.5)


if __name__ == '__main__':
    work_thread = threading.Thread(target=work)
    work_thread.start()
    time.sleep(1)
    print("主线程结束...")

结果输出:

img

2、设置守护主线程

主线程结束子线程自动销毁

方法:线程对象 = threading.Thread(target=函数名,daemon=True)

或者 线程对象.setDaemon(True)

代码部分

"""
@time:2022-03-29
@desc:
    设置守护主线程
    主线程结束 子线程自动销毁
"""
import time
import threading


# word函数
def work():
    for i in range(5):
        print("工作中...")
        time.sleep(0.5)


if __name__ == '__main__':
    # 方法一:
    # work_thread = threading.Thread(target=work, daemon=True)

    # 方法二:
    work_thread = threading.Thread(target=work)
    work_thread.setDaemon(True)

    work_thread.start()
    time.sleep(1)
    print("主线程结束...")

结果输出:

img

线程间的执行顺序

线程之间的执行顺序是无序的,由CPU调度

代码部分

"""
@time:2022-03-29
@desc:
    线程间执行顺序
"""
import threading
import time


def task():
    time.sleep(1)
    # current_thread 获取当前线程的线程对象
    thread = threading.current_thread()
    print(thread)


if __name__ == '__main__':
    for i in range(5):
        sub_thread = threading.Thread(target=task)
        sub_thread.start()

结果输出:

img

进程与线程的对比

关系对比

  • 线程是依附在进程里面的,没有进程就没有线程
  • 一个进程默认提供一条线程,进程可以创建多个线程

img

区别对比

  • 创建进程的资源开销要比创建线程的资源开销要大
  • 进程是操作系统资源分配的基本单元,线程是CPU调度的基本单元
  • 线程不能独立运行,必须依附在进程中

优缺点对比

1、进程的优缺点

优点:可以用多核

缺点:资源开销大

2、线程优缺点

优点:资源开销小

缺点:不能使用多核

案例

import os
import threading
def copy_file(file_name, source_dir, dest_dir):
    # 1 拼接源文件路径和目标文件路径
    source_path = source_dir + '\\' + file_name
    dest_path = dest_dir + '\\' + file_name
    # 2 打开源文件和目标文件
    with open(source_path, 'rb') as source_file:
        with open(dest_path, 'wb') as dest_file:
            # 3 循环读取源文件到目标路径
            while True:
                data = source_file.read(1024)
                if data:
                    dest_file.write(data)
                else:
                    break
if __name__ == '__main__':
    # 1 定义源文件夹和目标文件夹
    source_dir = r'F:\迅雷下载\视频-智能机器人从0到1系统入门课程\视频'
    dest_dir= r'F:\目标文件夹'

    # 2.创建目标文件夹
    try:
        os.mkdir(dest_dir)
    except:
        print("目标文件夹已经存在")
    # 3.读取源文件夹的文件列表
    file_list = os.listdir(source_dir)
    # 4.遍历文件列表实现拷贝
    for file_name in file_list:
        # copy_file(file_name, source_dir, dest_dir)
        # 5.使用多线程实现多任务拷贝
        sub_thread = threading.Thread(target=copy_file, args=(file_name, source_dir, dest_dir))
        sub_thread.start()
分类: Python

评论

-- 评论已关闭 --

目录