我奶奶都能看懂系列016Python进程和线程的使用

Posted 毛毛是一只狗

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了我奶奶都能看懂系列016Python进程和线程的使用相关的知识,希望对你有一定的参考价值。

🌌 专注Golang,Python语言,云原生,人工智能领域得博主;
💜 过去经历的意义在于引导你,而非定义你;
📢 欢迎点赞 👍 收藏 ⭐留言!

01-多进程的使用

# 1. 导包
import multiprocessing
import time


# 2.1 定义任务函数 唱歌
def sing():
    # 循环只执行了 5 次,在一个时间片内就执行结束了
    for i in range(5):
        print('正在唱歌.....')
        # 执行一次唱歌之后,代码实现,手动的失去 CPU,切换任务, time.sleep()
        time.sleep(0.1)  # 让程序休眠 0.1秒, 进程会进入阻塞态,失去 CPU


# 2.2 跳舞
def dance():
    for i in range(5):
        print('正在跳舞....')
        time.sleep(0.1)


if __name__ == '__main__':
    # 2. 创建进程对象
    # target 参数指定进程执行的任务,参数需要是函数, 并且是函数名, 不能加括号,
    process_1 = multiprocessing.Process(target=sing)   # 创建进程,分配任务,sing
    process_2 = multiprocessing.Process(target=dance)   # 创建进程,分配任务,sing
    # 3. 启动的进程, 相当于是让进程处于就绪态,等待 CPU 分配时间
    process_1.start()
    process_2.start()

02-获取进程编号

# 1. 导包
import multiprocessing
import time
import os


# 2.1 定义任务函数 唱歌
def sing():
    # 循环只执行了 5 次,在一个时间片内就执行结束了
    print('sing:', multiprocessing.current_process(), multiprocessing.current_process().pid)   # process-1
    # os.getpid 获取当前进程的 id  os.getppid() 获取父进程的 id
    print(f'sing, pid os.getpid(), ppidos.getppid()')
    for i in range(5):
        print('正在唱歌.....')
        # 执行一次唱歌之后,代码实现,手动的失去 CPU,切换任务, time.sleep()
        time.sleep(0.1)  # 让程序休眠 0.1秒, 进程会进入阻塞态,失去 CPU
        os.kill(os.getpid(), 9)  # 杀死当前进程,


# 2.2 跳舞
def dance():
    print('dance:', multiprocessing.current_process(), multiprocessing.current_process().pid)   # process-2
    print(f'dance, pid os.getpid(), ppidos.getppid()')

    for i in range(5):
        print('正在跳舞....')
        time.sleep(0.1)


if __name__ == '__main__':
    # 程序启动,默认会有一个进程,主进程
    # 2. 创建进程对象
    # target 参数指定进程执行的任务,参数需要是函数, 并且是函数名, 不能加括号,
    # 进程对象.name  获取进程的名字, 进程对象.pid 能够获取进程对象的进程 id
    # multiprocessing.current_process()  获取当前的进程对象
    print('main:', multiprocessing.current_process(), multiprocessing.current_process().pid)   # 主进程执行
    print(f'main, pid os.getpid(), ppidos.getppid()')

    process_1 = multiprocessing.Process(target=sing)   # 创建进程,分配任务,sing
    process_2 = multiprocessing.Process(target=dance)   # 创建进程,分配任务,sing
    # 3. 启动的进程, 相当于是让进程处于就绪态,等待 CPU 分配时间
    process_1.start()
    process_2.start()

03-进程传参

# 1. 导包
import multiprocessing
import time


# 2.1 定义任务函数 唱歌
def sing(singer, song):
    # 循环只执行了 5 次,在一个时间片内就执行结束了
    for i in range(5):
        print(f'singer正在唱song.....')
        # 执行一次唱歌之后,代码实现,手动的失去 CPU,切换任务, time.sleep()
        time.sleep(0.1)  # 让程序休眠 0.1秒, 进程会进入阻塞态,失去 CPU


# 2.2 跳舞
def dance(dancer, name):
    for i in range(5):
        print(f'dancer正在跳name_____________')
        time.sleep(0.1)


if __name__ == '__main__':
    # 2. 创建进程对象
    # 由于进程执行的任务函数,sing 和 dance 都有形参,所有在创建对象的时候需要传递实参
    # 方式一, args 形参, 实参值需要是元组类型,
    process_1 = multiprocessing.Process(target=sing, args=('毛不易', '消愁'))   # 创建进程,分配任务,sing
    # 方式二, kwargs 形参, 实参值需要是字典,字典的 key 是任务函数的形参名,
    process_2 = multiprocessing.Process(target=dance,
                                        kwargs='dancer': '罗老师', 'name': '精武门')   # 创建进程,分配任务,sing
    # 3. 启动的进程, 相当于是让进程处于就绪态,等待 CPU 分配时间
    process_1.start()
    process_2.start()

04-进程不共享全局变量

# 1. 导包
import multiprocessing
import time

# 定义全局变量
g_list = []


# 2.1 定义进程执行的任务函数
def write_data():
    for i in range(5):
        g_list.append(i)
        print('添加数据成功', i)

    # 代码执行到此,代表 5 个数据添加完成
    print(f"write_data: g_list")


def read_data():
    print(f"read: g_list")


if __name__ == '__main__':
    # g_list = []
    # 2. 创建进程对象
    write_process = multiprocessing.Process(target=write_data)
    read_process = multiprocessing.Process(target=read_data)
    # 3. 启动进程
    write_process.start()
    write_process.join()   # 1. 主进程阻塞等待  2. 等等待write_process 执行完成
    read_process.start()
    # 需求: 主进程在最后打印 g_list 值
    # 解决方案: 使用 进程对象.join() 方法, 阻塞等待进程执行完成
    # 1. 谁阻塞等待, 这行代码写在哪,哪个进程就阻塞等待
    # 2. 等待谁执行完成, 哪个对象调用这个方法,就是等待哪个对象执行完成
    print(f"main: g_list")

05-主进程会会等待子进程结束再结束

import multiprocessing
import time


def func():
    for i in range(5):
        print('子进程', i)
        time.sleep(0.5)  # 子进程至少需要 2.5 秒才能结束

    print('子进程代码结束,即活干完了')


if __name__ == '__main__':
    sub_process = multiprocessing.Process(target=func)
    sub_process.start()
    time.sleep(1)   # 主进程至少需要 1 秒结束
    print('主进程的代码结束, 即活干完了')  # 主进程结束,程序就结束了

06-让子进程随着主进程的结束而结束

import multiprocessing
import time
import sys


def func():
    for i in range(5):
        print('子进程', i)
        time.sleep(0.5)  # 子进程至少需要 2.5 秒才能结束

    print('子进程代码结束,即活干完了')


if __name__ == '__main__':
    sub_process = multiprocessing.Process(target=func)
    # 方案二 将子进程对象设置为 daemon 进程
    # sub_process.daemon = True   # 修改对象的属性
    sub_process.start()
    time.sleep(1)   # 主进程至少需要 1 秒结束
    print('主进程的代码结束, 即活干完了')  # 主进程结束,程序就结束了
    # 主进程结束了,想让子进程一块结束,
    #  方案一
    # sub_process.terminate()  # 终止子进程的执行
    # exit()   # 让进程退出
    sys.exit()

07-多线程的使用

# 1. 导包
import threading
import time


# 2.1 定义任务函数 唱歌
def sing():
    print("sing", threading.current_thread().name)
    # 循环只执行了 5 次,在一个时间片内就执行结束了
    for i in range(5):
        print('正在唱歌.....')
        time.sleep(0.1)  # 让程序休眠 0.1秒, 进程会进入阻塞态,失去 CPU


# 2.2 跳舞
def dance():
    print("dance", threading.current_thread().name)
    for i in range(5):
        print('正在跳舞....')
        time.sleep(0.1)


if __name__ == '__main__':
    # 2. 创建线程对象
    print("main", threading.current_thread().name)
    thread_1 = threading.Thread(target=sing)
    thread_2 = threading.Thread(target=dance)
    # 3. 启动线程
    thread_1.start()
    thread_2.start()

08-线程传参

# 1. 导包
import threading
import time


# 2.1 定义任务函数 唱歌
def sing(singer, song):
    print("sing", threading.current_thread().name)
    # 循环只执行了 5 次,在一个时间片内就执行结束了
    for i in range(5):
        print(f'singer正在唱歌 song.....')
        time.sleep(0.1)  # 让程序休眠 0.1秒, 进程会进入阻塞态,失去 CPU


# 2.2 跳舞
def dance(dancer, name):
    print("dance", threading.current_thread().name)
    for i in range(5):
        print(f'dancer正在跳舞name....')
        time.sleep(0.1)


if __name__ == '__main__':
    # 2. 创建线程对象
    print("main", threading.current_thread().name)
    thread_1 = threading.Thread(target=sing, kwargs='singer': '毛不易', 'song': '消愁')
    thread_2 = threading.Thread(target=dance, args=('罗老师', '精武门'))
    # 3. 启动线程
    thread_1.start()
    thread_2.start()


09-线程的执行是无序的

# 1. 导包
import threading
import time


# 2.1 定义线程执行的任务函数
def func():
    time.sleep(1)
    print(threading.current_thread().name)


if __name__ == '__main__':
    # 循环创建线程
    for i in range(10):
        # 2. 创建线程对象
        sub_process = threading.Thread(target=func)
        # 3. 启动线程
        sub_process.start()

10-主线程会等待子线程结束在结束

import threading
import time


def func():
    for i in range(5):
        print(threading.current_thread().name, i)
        time.sleep(0.5)  # 2.5 s

    print('子线程的任务结束')


if __name__ == '__main__':
    sub_thread = threading.Thread(target=func)
    sub_thread.start()
    time.sleep(1)
    print('主线程的任务结束了')

11-让子线程随着主线程的结束而结束

import threading
import time


def func():
    for i in range(5):
        print(threading.current_thread().name, i)
        time.sleep(0.5)  # 2.5 s

    print('子线程的任务结束')


if __name__ == '__main__':
    # 想让子线程随着主线程结束而结束,可以将子线程设置为 daemon 线程
    # 方法一, 在创建对象的时候,设置
    # sub_thread = threading.Thread(target=func, daemon=True)
    sub_thread = threading.Thread(target=func)
    # 方法二
    # sub_thread.daemon = True
    sub_thread.setDaemon(True)
    sub_thread.start()
    time.sleep(1)
    print('主线程的任务结束了')

12-同一个进程中的线程共享全局变量

import threading

g_list = []


def write():
    for i in range(5):
        g_list.append(i)
        print('添加数据', i)

    print('write:', g_list)


def read():
    print('read:', g_list)


if __name__ == '__main__':
    write_thread = threading.Thread(target=write)
    read_thread = threading.Thread(target=read)
    write_thread.start()
    read_thread.start()
    print('main:', g_list)

13-线程共享全局变量的问题

import threading

# 定义全局变量
g_num = 0


# 定义任务函数
def func():
    global g_num   # 声明使用全局变量
    for i in range(1000000):
        g_num += 1

    # 当子线程中的代码执行到此, 代表子线程的 100万次加 1 完成
    print(threading.current_thread().name, g_num)


if __name__ == '__main__':
    sub_thread1 = threading.Thread(target=func)
    sub_thread2 = threading.Thread(target=func)
    sub_thread1.start()
    sub_thread2.start()
    sub_thread1.join()  # 等待线程 1 执行结束
    sub_thread2.join()  # 等待线程 2 执行结束
    print('main:', g_num)

以上是关于我奶奶都能看懂系列016Python进程和线程的使用的主要内容,如果未能解决你的问题,请参考以下文章

我奶奶都能看懂系列013python基础语法——类3

我奶奶都能看懂系列007☀️python基础语法——函数,小学生也可以学!

我奶奶都能看懂系列002☀️python基础语法,小学生也可以学!

我奶奶都能看懂系列005☀️python基础语法——容器,小学生也可以学!

小白都能看懂的实战教程 手把手教你Python Web全栈开发 (DAY 2)

人人都能看懂系列:《分布式系统改造方案——老旧系统改造篇》