【黑马程序员】Python多任务

文章目录

多进程

多进程使用流程

导入包

python 复制代码
import multiprocessing

Process进程类说明

  • 语法
text 复制代码
Process({group [, target [, name [, args [,kwargs]]]]})
group:指定进程组,目前只能使用None
target:执行的目标任务名
name:进程名字
args:以元组形式给执行任务传参
kwargs:以字典形式给执行任务传参
  • Process创建实例对象的常用方法
    • start():创建子进程
    • join():等待子进程执行结束
    • terminate():不管任务是否完成,立即终止子进程
  • Process创建的实例对象的常用属性
    • name:当前进程的别名,默认为Process-N,N为从1开始递增的整数
  • 代码示例
python 复制代码
# *_*coding:utf-8 *_*
import multiprocessing
import time


def sing(msg):
    for i in range(5):
        print(f"{msg}")
        time.sleep(1)


def dance(msg):
    for i in range(5):
        print(f'{msg}')
        time.sleep(1)


if __name__ == '__main__':
    # 单进程:需要至少10s钟完成
    # sing("sing")
    # dance("dance")

    # 三个进程:1个主进程,2个子进程
    # 创建子进程方式
    # target为任务名,创建一个sing线程,通过元组方式传参
    sing_obj = multiprocessing.Process(target=sing, args=("sing sing sing",))
    # target为任务名,创建一个dance线程,通过字段方式传参
    dance_obj = multiprocessing.Process(target=dance, kwargs={"msg": "dance dance dance"})
    # 启动两个线程
    sing_obj.start()
    dance_obj.start()

获取进程编号

目的

  • 获取进程编号的目的是验证主进程与子进程的关系,得知子进程是由哪个主进程创建出来的

常用操作

  • 获取当前进程编号:os.getpid()
  • 回去当前父进程编号:os.getppid
  • 代码示例
python 复制代码
# *_*coding:utf-8 *_*
import multiprocessing
import os


def sing():
    # 获取当前进程编号
    print("sing当前进程编号: ", os.getpid())
    # 获取当前进程
    print("sing 当前进程: ", multiprocessing.current_process())
    # 获取当前父进程编号
    print("sing父进程编号: ", os.getppid())


if __name__ == '__main__':
    # 获取主进程ID
    print("main当前进程编号: ", os.getpid())
    obj = multiprocessing.Process(target=sing)
    obj.start()

获取进程名

  • 创建子进程时,使用name给子进程起名
  • 代码示例
python 复制代码
# *_*coding:utf-8 *_*
import multiprocessing


def sing():
    # 获取当前进程名
    print("sing 当前进程: ", multiprocessing.current_process())


if __name__ == '__main__':
    # 获取主进程ID
    obj = multiprocessing.Process(target=sing, name="test_dance")
    obj.start()

进程注意点

进程之间不共享全局变量

  • 进程是分配资源的最小单位,每个进程都会有自己的独立空间
  • 创建子进程会对主进程资源进行拷贝,也就是说子进程是主进程的一个副本,之所以进程之间不共享全局变量,是因为操作的不是一个进程里面的全局变量,只不过不同进程里面的全局变量名字相同而已
  • 代码示例
python 复制代码
# *_*coding:utf-8 *_*
import multiprocessing
import time

# 定义全局变量
g_num = 0


def my_read():
    print("my_read:", g_num)


def my_write():
    # 向全局变量中写数据
    global g_num
    g_num = 10
    print("my_write:", g_num)


if __name__ == '__main__':
    # 创建子进程
    read_obj = multiprocessing.Process(target=my_read)
    write_obj = multiprocessing.Process(target=my_write)
    # 开启子进程
    write_obj.start()
    # 保证全局变量数据被写入
    time.sleep(1)
    read_obj.start()

主进程会等待子进程结束之后再结束

  • 代码示例
python 复制代码
# *_*coding:utf-8 *_*
import multiprocessing
import time


def func():
    for i in range(5):
        time.sleep(0.3)
        print("func()")


if __name__ == '__main__':
    obj = multiprocessing.Process(target=func)
    obj.start()
    print("main")
    exit(0)

设置守护主进程

  • 设置守护主进程的目的是,主进程退出子进程销毁,不让主进程等待子进程去执行
  • 设置守护主进程方式:子进程对象.daemon=true
  • 销毁子进程方式:子进程对象.terminate()
  • 注意:需要在子进程start之前设置

多线程

  • 线程是使用资源的最小单位,依附于进程

threading模块

  • Python的多线程可以通过threading模块来实现
  • 语法
python 复制代码
import threading

thread_obj = threading.Thread([group[, target[, name[, args[, kwargs]]]]])
group:预留参数,暂未使用
target:执行的目标任务名
args:以元组的方式给执行任务传参
kwargs:以字典的方式给执行任务传参
name:线程名,一般不设置

# 启动线程
thread_obj.start()
  • 代码示例
python 复制代码
# *_*coding:utf-8 *_*

import time
import threading


def sing(msg):
    while True:
        print(f"{msg}")
        time.sleep(1)


def dance(msg):
    while True:
        print(f'{msg}')
        time.sleep(1)


if __name__ == '__main__':
    # 创建一个sing线程,通过元组方式传参
    sing_thread_obj = threading.Thread(target=sing, args=("sing sing sing",))
    # 创建一个dance线程,通过字段方式传参
    dance_thread_obj = threading.Thread(target=dance, kwargs={"msg": "dance dance dance"})
    # 启动两个线程
    sing_thread_obj.start()
    dance_thread_obj.start()

线程注意点

线程之间执行是无序的

  • 代码示例
python 复制代码
# *_*coding:utf-8 *_*
import threading
import time


def func():
    # sleep的时候CPU是空闲的,所有创建出来的线程都在等待CPU的执行
    time.sleep(0.3)
    # 实际执行线程位置
    print(threading.current_thread())


if __name__ == '__main__':
    for _ in range(5):
        # 创建线程位置
        my_func = threading.Thread(target=func)
        my_func.start()

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

  • 未设置守护线程代码示例
python 复制代码
# *_*coding:utf-8 *_*
import threading
import time


def func():
    for _ in range(5):
        time.sleep(0.2)
        print("func")


if __name__ == '__main__':
    obj = threading.Thread(target=func)
    obj.start()
    time.sleep(0.5)
    print("main over")
  • 设置守护线程
    • 守护线程就是主线程退出子线程销毁不再执行
  • 设置方式
    • 方式一:threading.Thread(target=方法名, daemon=True)
    • 方式二:线程对象.setDaemon(True)
  • 代码示例
python 复制代码
# *_*coding:utf-8 *_*
import threading
import time


def func():
    for _ in range(5):
        time.sleep(0.2)
        print("func")


if __name__ == '__main__':
    # # 不设置守护线程方式
    # obj = threading.Thread(target=func)
    # # 设置守护线程方式一
    # obj = threading.Thread(target=func, daemon=True)
    obj = threading.Thread(target=func)
    # 设置守护线程方式二
    obj.setDaemon(True)
    obj.start()
    time.sleep(0.5)
    print("main over")

线程之间共享全局变量

python 复制代码
# *_*coding:utf-8 *_*
import threading
import time

g_num = []


def my_read():
    global g_num
    print("my_read: ", g_num)


def my_write():
    global g_num
    for i in range(5):
        g_num.append(i)

    print("my_write: ", g_num)


if __name__ == '__main__':
    print("main start: ", g_num)
    write_obj = threading.Thread(target=my_write)
    read_obj = threading.Thread(target=my_read)
    write_obj.start()
    # 确保write先执行
    time.sleep(0.1)
    read_obj.start()
    print("main finish: ", g_num)

线程之间共享全局变量数据出现错误问题

  • 代码示例
python 复制代码
# *_*coding:utf-8 *_*
import threading

g_num = 0


def func1():
    global g_num
    for _ in range(1000000):
        g_num += 1
    print("func1: ", g_num)


def func2():
    global g_num
    for _ in range(1000000):
        g_num += 1
    print("func2: ", g_num)


if __name__ == '__main__':
    obj1 = threading.Thread(target=func1)
    obj2 = threading.Thread(target=func2)
    obj1.start()
    obj2.start()
    print(g_num)

多线程共享全局变量问题

线程等待

  • 语法:子线程.join()
  • 功能:让主线程等待当前子线程执行完毕在继续向下执行
  • 代码示例
python 复制代码
# *_*coding:utf-8 *_*
import threading

g_num = 0


def func1():
    global g_num
    for _ in range(1000000):
        g_num += 1
    print("func1: ", g_num)


def func2():
    global g_num
    for _ in range(1000000):
        g_num += 1
    print("func2: ", g_num)


if __name__ == '__main__':
    obj1 = threading.Thread(target=func1)
    obj2 = threading.Thread(target=func2)
    obj1.start()
    obj1.join()
    obj2.start()
    obj2.join()
    print(g_num)

互斥锁

  • 对共享数据进行锁定,保证同一时刻只能有一个线程去操作
  • 基本使用语法
python 复制代码
# 创建锁
mutex = threading.Lock()
# 上锁
mutex.acquire()
# 释放锁
mutex.release()
  • 代码示例
python 复制代码
# *_*coding:utf-8 *_*
import threading

g_num = 0

# 创建锁
mutex = threading.Lock()


def func1():
    global g_num
    # 加锁
    mutex.acquire()
    for _ in range(1000000):
        g_num += 1
    # 释放锁
    mutex.release()
    print("func1: ", g_num)


def func2():
    global g_num
    # 加锁
    mutex.acquire()
    for _ in range(1000000):
        g_num += 1
    # 释放锁
    mutex.release()
    print("func2: ", g_num)


if __name__ == '__main__':
    obj1 = threading.Thread(target=func1)
    obj2 = threading.Thread(target=func2)
    obj1.start()
    obj2.start()
相关推荐
爱吃生蚝的于勒2 分钟前
深入学习指针(5)!!!!!!!!!!!!!!!
c语言·开发语言·数据结构·学习·计算机网络·算法
binishuaio12 分钟前
Java 第11天 (git版本控制器基础用法)
java·开发语言·git
zz.YE13 分钟前
【Java SE】StringBuffer
java·开发语言
就是有点傻18 分钟前
WPF中的依赖属性
开发语言·wpf
洋24026 分钟前
C语言常用标准库函数
c语言·开发语言
进击的六角龙28 分钟前
Python中处理Excel的基本概念(如工作簿、工作表等)
开发语言·python·excel
wrx繁星点点29 分钟前
状态模式(State Pattern)详解
java·开发语言·ui·设计模式·状态模式
NoneCoder1 小时前
Java企业级开发系列(1)
java·开发语言·spring·团队开发·开发
苏三有春1 小时前
PyQt5实战——UTF-8编码器功能的实现(六)
开发语言·qt
一只爱好编程的程序猿1 小时前
Java后台生成指定路径下创建指定名称的文件
java·python·数据下载