python多线程编程-基础篇

一、学前须知

1、需掌握python基础语法、python文件操作、python模块应用

2、开发工具:pycharm、python3.6及以上版本

3、学习内容:进程、线程、多任务应用

二、多任务介绍

2.1概念:

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

2.2多任务的两种表现形式

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

在这里插入图片描述

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

在这里插入图片描述

三、进程

3.1进程的概念:

进程是资源分配的最小单位,他是操作系统进行资源分配和调度运行的基本单位。通俗理解:一个正在运行的一个程序就是一个进程。例如:正在运行的qq、wechat等,它们都是一个进程。

3.2多进程的作用

在这里插入图片描述
在这里插入图片描述

3.3进程的创建步骤

  1. 导入进程包

    import multiprocessing

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

    进程对象 = multiprocessing.Process()

  3. 启动进程执行任务

    进程对象.start()

3.3通过进程类创建进程对象

在这里插入图片描述

3.4单任务和多任务简单例子

  • 单任务

    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__':
        time1 = time.time()
        sing()
        dance()
        print(time.time()-time1)
    

    ​ 输出结果

    唱歌。。。
    唱歌。。。
    唱歌。。。
    跳舞。。。
    跳舞。。。
    跳舞。。。
    3.0027265548706055

  • 使用多进程实现多任务

    import multiprocessing
    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__':
        time1 = time.time()
        s1 = multiprocessing.Process(target=sing)
        d1 = multiprocessing.Process(target=dance)
        s1.start()
        d1.start()
        s1.join() #这个方法可以等待子进程结束后再继续往下运行,通常用于进程间的同步
        d1.join()
        print(time.time()-time1)
    

    输出结果

    唱歌。。。
    跳舞。。。
    唱歌。。。
    跳舞。。。
    唱歌。。。
    跳舞。。。
    1.7515902519226074

3.5 进程执行带有参数的任务

在这里插入图片描述

import multiprocessing
import time

def sing(name, num):
    for i in range(num):
        print("%s在唱歌。。。"%name)
        time.sleep(0.5)
def dance(num):
    for i in range(num):
        print("跳舞。。。")
        time.sleep(0.5)
if __name__ == '__main__':
    # 以元组形式传参
    s1 = multiprocessing.Process(target=sing, args=('小明', 3))
    # 以字典形式传参
    d1 = multiprocessing.Process(target=dance, kwargs={"num": 5, })
    s1.start()
    d1.start()
注意事项
  • 元组传参一定要和参数顺序一致
  • 字典方式传参时字典的key要和参数名一致

3.6获取进程编号

进程编号的作用:

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

获取进程编号的两种方式:

  1. 获取当前进程编号

    os.getpid()

  2. 获取当前父进程编号

    os.getppid()

import multiprocessing
import time
import os
def sing(name, num):
    print("唱歌进程的编号: ", os.getpid())
    print("唱歌进程的父进程的编号: ", os.getppid())
    for i in range(num):
        print("%s在唱歌。。。"%name)
        time.sleep(0.5)
def dance(num):
    print("跳舞进程的编号: ", os.getpid())
    print("跳舞进程的父进程的编号: ", os.getppid())
    for i in range(num):
        print("跳舞。。。")
        time.sleep(0.5)
if __name__ == '__main__':
    print("主进程的编号: ", os.getpid())
    # 以元组形式传参   顺序和参数顺序一致
    s1 = multiprocessing.Process(target=sing, args=('小明', 3))
    # 以字典形式传参   key和参数名保持一致
    d1 = multiprocessing.Process(target=dance, kwargs={"num": 5, })
    s1.start()
    d1.start()

输出结果:

主进程的编号: 10620
唱歌进程的编号: 18412
唱歌进程的父进程的编号: 10620
小明在唱歌。。。
跳舞进程的编号: 9924
跳舞进程的父进程的编号: 10620
跳舞。。。
小明在唱歌。。。
跳舞。。。
小明在唱歌。。。
跳舞。。。
跳舞。。。
跳舞。。。

3.7进程的注意点

  • 主进程会等待所有的子进程执行结束在结束

import time
import multiprocessing

def work():
    for i in range(10):
        print("工作中。。。。")
        time.sleep(0.2)

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

    time.sleep(1)
    print("主进程执行结束")

输出结果:

工作中。。。。
工作中。。。。
工作中。。。。
工作中。。。。
主进程执行结束
工作中。。。。
工作中。。。。
工作中。。。。
工作中。。。。
工作中。。。。
工作中。。。。

  • 设置守护主进程

主进程结束后不会再继续执行子进程中剩余的工作

import time
import multiprocessing

def work():
    for i in range(10):
        print("工作中。。。。")
        time.sleep(0.2)

if __name__ == '__main__':
    # 设置守护主进程,主进程执行完成,则结束
    # 方式1
    work_process = multiprocessing.Process(target=work, daemon=True)
    # 方式2
    # work_process.daemon = True
    work_process.start()

    time.sleep(1)
    print("主进程执行结束")

输出结果:

工作中。。。。
工作中。。。。
工作中。。。。
工作中。。。。
主进程执行结束

3.8案例-多进程实现视频文件夹多任务拷贝器

  1. 需求分析:
    • 目标文件夹是否存在,如果不存在就创建,存在则不创建
    • 遍历源文件夹中所有文件,并拷贝到目标文件夹
    • 采用进程实现多任务,并完成拷贝
  2. 实现步骤
    • 定义源文件夹所在的路径,目标文件夹所在路径
    • 创建目标文件夹
    • 通过os.listdir获取源目录中的文件列表
    • 遍历每个文件,定义一个函数,专门实现文件拷贝
    • 采用进程实现多任务,完成高并发拷贝
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()

四、线程

4.1线程的介绍

  • 实现多任务的另一种形式
  • 线程是程序执行的最小单位
  • 同属一个进程的多个线程共享进程所拥有的全部资源

在这里插入图片描述

4.2线程的创建步骤

  1. 导入线程包

    import threading

  2. 通过线程类创建进程对象

    线程对象 = threading.Thread()

  3. 启动线程执行任务

    线程对象.start()

4.3通过线程类创建线程对象

在这里插入图片描述

4.4 线程用法与进程用法一致,此处不再赘述

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()

4.5线程之间的执行顺序:

无序,由CPU调度决定某个线程先执行

五、进程和线程对比

5.1关系对比

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

5.2区别对此

  1. 创建进程的资源开销要比创建线程的资源开销要大
  2. 进程是操作系统资源分配的基本单位,线程是CPU调度的基本单位
  3. 线程不能够独立执行,必须依存在进程中

5.3优缺点对比

  1. 进程优缺点:
    • 优点:可以用多核
    • 缺点:资源开销大
  2. 线程优缺点:
    • 优点:资源开销小
    • 缺点:不可用多核
  • 43
    点赞
  • 91
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值