多线程.多进程

1.multiprocessing获取进程ID/编号

# 1. 导入进程包
import multiprocessing
import time
import os


# 跳舞任务
def dance():
    # 获取当前进程(子进程)的编号
    dance_process_id = os.getpid()
    # 获取当前进程对象,查看当前代码是由那个进程执行的 : multiprocessing.current_process()
    print("dance_process_id:", dance_process_id, multiprocessing.current_process())
    # 获取当前进程的父进程编号
    dance_process_parent_id = os.getppid()
    print("dance_process的父进程编号是:", dance_process_parent_id)

    for i in range(3):
        print("跳舞中...")
        time.sleep(0.2)
        # 扩展: 根据进程编号强制杀死指定进程
        os.kill(dance_process_id, 9)


# 唱歌任务
def sing():
    # 获取当前进程(子进程)的编号
    sing_process_id = os.getpid()
    # 获取当前进程对象,查看当前代码是由那个进程执行的 : multiprocessing.current_process()
    print("sing_process_id:", sing_process_id, multiprocessing.current_process())

    # 获取当前进程的父进程编号
    sing_process_parent_id = os.getppid()
    print("sing_process的父进程编号是:", sing_process_parent_id)

    for i in range(3):
        print("唱歌中...")
        time.sleep(0.2)

if __name__ == '__main__':
    # 获取当前进程(主进程)的编号
    main_process_id = os.getpid()
    # 获取当前进程对象,查看当前代码是由那个进程执行的 : multiprocessing.current_process()
    print("main_process_id:", main_process_id, multiprocessing.current_process())

    # 2. 创建子进程(自己手动创建的进程称为子进程, 在__init__.py文件中已经导入的Process类)
    # 1. group: 进程组,目前只能使用None,一般不需要设置
    # 2. target: 进程执行的目标任务
    # 3. name: 进程名,如果不设置,默认是Process-1, ......
    dance_process = multiprocessing.Process(target=dance, name="dance_process")
    print("dance_process:", dance_process)
    sing_process = multiprocessing.Process(target=sing, name="sing_process")
    print("sing_process:", sing_process)

    # 3. 启动进程执行对应的任务
    dance_process.start()
    sing_process.start()

    # 进程执行是无序的,具体那个进程先执行是由操作系统调度决定

2.multiprocessing的terminate()守护主进程

import multiprocessing
import time


def task():
    # for i in range(10):
    while True:
        print("任务执行中...")
        time.sleep(0.2)


# 判断是否是直接执行的模块, 程序入口模块

# 标准python写法,直接执行的模块,需要加上判断是否是主模块的代码
if __name__ == '__main__':

    # 创建子进程
    sub_process = multiprocessing.Process(target=task)
    # 把子进程设置成为守护主进程,以后主进程退出子进程直接销毁
    # sub_process.daemon = True
    sub_process.start()

    # 主进程延时0.5秒钟
    time.sleep(0.5)
    # 退出主进程之前,先让子进程进行销毁
    sub_process.terminate()#terminate --> 停止,结束
    print("over")

# 结论: 主进程会等待子进程执行完成以后程序再退出

# 解决办法: 主进程退出子进程销毁
# 1. 让子进程设置成为守护主进程,主进程退出子进程销毁,子进程会依赖主进程
# 2. 让主进程退出之前先让子进程销毁

3.threading的获取当前线程编号/ID

# 1. 导入线程模块
import threading
import time


def sing():
    # 获取当前线程
    current_thread = threading.current_thread()#current --> 现在发生的,当前的
    print("sing:", current_thread)

    for i in range(3):
        print("唱歌中...")
        time.sleep(0.2)


def dance():
    # 获取当前线程
    current_thread = threading.current_thread()
    print("dance:", current_thread)

    for i in range(3):
        print("跳舞中...")
        time.sleep(0.2)


if __name__ == '__main__':

    # 获取当前线程
    current_thread = threading.current_thread()
    print("main_thread:", current_thread)

    # 2. 创建子线程
    sing_thread = threading.Thread(target=sing, name="sing_thread")
    dance_thread = threading.Thread(target=dance, name="dance_thread")
    # 3. 启动子线程执行对应的任务
    sing_thread.start()
    dance_thread.start()

4.threading的setDaemon()设置守护线程

import threading
import time


def task():
    while True:
        print("任务执行中...")
        time.sleep(0.3)

if __name__ == '__main__':
    # 创建子线程
    # daemon=True 表示创建的子线程守护主线程,主线程退出子线程直接销毁
    # sub_thread = threading.Thread(target=task, daemon=True)
    sub_thread = threading.Thread(target=task)
    # 把子线程设置成为守护主线程
    sub_thread.setDaemon(True)#Daemon --> 守护线程
    sub_thread.start()

    # 主线程延时执行1秒
    time.sleep(1)

    print("over")
    # exit()

# 结论: 主线程会等待子线程执行结束再结束

# 解决办法: 把子线程设置成为守护主线程即可

5.threading的共享全局变量及线程等待join()的使用

import threading
import time


# 定义全局变量
g_list = []


# 添加数据的任务
def add_data():
    for i in range(3):
        # 每循环一次把数据添加到全局变量
        g_list.append(i)
        print("add:", i)
        time.sleep(0.3)

    # 代码执行到此,说明添加数据完成
    print("添加数据完成:", g_list)


# 读取数据的任务
def read_data():
    print("read:", g_list)


if __name__ == '__main__':
    # 创建添加数据的子线程
    add_thread = threading.Thread(target=add_data)
    # 创建读取数据的子线程
    read_thread = threading.Thread(target=read_data)

    # 启动线程执行对应的任务
    add_thread.start()
    # time.sleep(1)
    # 让当前线程(主线程)等待添加数据的子线程执行完成以后代码在继续执行
    add_thread.join()
    read_thread.start()

# 结论: 线程之间共享全局变量

6.threading的互斥锁acquire()

import threading


# 全局变量
g_num = 0


# 创建互斥锁, Lock本质上是一个函数,通过调用函数可以创建一个互斥锁
lock = threading.Lock()


# 循环100万次执行的任务
def task1():
    # 上锁
    lock.acquire()#acquire --> (通过努力、能力、行为表现)获得;购得;获得;得到
    for i in range(1000000):
        # 每循环一次给全局变量加1
        global g_num  # 表示要声明修改全局变量的内存地址
        g_num = g_num + 1  # g_num += 1

    # 代码执行到此,说明数据计算完成
    print("task1:", g_num)
    # 释放锁
    lock.release()


# 循环100万次执行的任务
def task2():
    # 上锁
    lock.acquire()
    for i in range(1000000):
        # 每循环一次给全局变量加1
        global g_num  # 表示要声明修改全局变量的内存地址
        g_num = g_num + 1  # g_num += 1

    # 代码执行到此,说明数据计算完成
    print("task2:", g_num)
    # 释放锁
    lock.release()


if __name__ == '__main__':
    # 创建两个子线程
    first_thread = threading.Thread(target=task1)
    second_thread = threading.Thread(target=task2)

    # 启动线程执行任务
    first_thread.start()

    second_thread.start()

    # 互斥锁可以保证同一时刻只有一个线程去执行代码,能够保证全局变量的数据没有问题
    # 线程等待和互斥锁都是把多任务改成单任务去执行,保证了数据的准确性,但是执行性能会下降

7.threading的死锁解决

# 死锁: 一直等待对方释放锁的情景叫做死锁
import threading


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


# 需求: 多线程同时根据下标在列表中取值,要保证同一时刻只能有一个线程去取值
def get_value(index):
    # 上锁
    lock.acquire()
    my_list = [1, 4, 6]
    # 判断下标是否越界
    if index >= len(my_list):
        print("下标越界:", index)
        # 取值不成功,也需要释放互斥锁,不要影响后面的线程去取值
        # 锁需要在合适的地方进行释放,防止死锁
        lock.release()
        return

    # 根据下标取值
    value = my_list[index]
    print(value)
    # 释放锁
    lock.release()


if __name__ == '__main__':
    # 创建大量线程,同时执行根据下标取值的任务
    for i in range(10):
        # 每循环一次创建一个子线程
        sub_thread = threading.Thread(target=get_value, args=(i,))
        # 启动线程执行任务
        sub_thread.start()

 

posted @ 2020-06-22 15:03  sewen  Views(77)  Comments(0Edit  收藏  举报