多任务编程——进程、线程

250 阅读7分钟
  • 多任务的执行方式:

    • 并行:指在同一时刻,有多条指令在多个处理器上同时执行。
    • 并发:在一段时间内交替去执行任务。
  • 多进程实现多任务一共分为三步走:

    • 导入进程包

      • import multiprocessing
    • 创建子进程并指定执行的任务

      • sub_process = multiprocessing.Process (target=任务名)
    • 启动进程执行任务

      • sub_process.start()
  • 获取进程编号:

    • os.getpid() 表示获取当前进程编号
    • os.getppid() 表示获取当前父进程编号
  • 进程执行带有参数的任务:

    • args 表示以元组的方式给执行任务传参
    • kwargs 表示以字典方式给执行任务传参
  • 进程的注意点:

    • 进程之间不共享全局变量
    • 主进程会等待所有的子进程执行结束再结束
  • 设置守护进程:

    • 为了保证子进程能够正常的运行,主进程会等所有的子进程执行完成以后再销毁,设置守护主进程的目的是主进程退出子进程销毁,不让主进程再等待子进程去执行
    • 设置守护主进程方式: 子进程对象.daemon = True
    • 销毁子进程方式: 子进程对象.terminate()
  • 多线程实现多任务一共分为三步走:

    • 导入线程模块

      • import threading
    • 创建子线程并指定执行的任务

      • sub_thread = threading.Thread(target=任务名)
    • 启动线程执行任务

      • sub_thread.start()
  • 线程的注意点:

    • 线程执行执行是无序的

    • 主线程默认会等待所有子线程执行结束再结束,设置守护主线程的目的是主线程退出子线程销毁。

    • 线程之间共享全局变量,好处是可以对全局变量的数据进行共享。

    • 线程之间共享全局变量可能会导致数据出现错误问题,可以使用线程同步方式来解决这个问题。

      • 线程等待(join)
    • 设置守护线程:

      • 守护主线程就是主线程退出子线程销毁不再执行

      设置守护主线程有两种方式:

      1. threading.Thread(target=show_info, daemon=True)
      2. 线程对象.setDaemon(True)
  • 进程与线程对比:

    • 进程和线程都是完成多任务的一种方式
    • 多进程要比多线程消耗的资源多,但是多进程开发比单进程多线程开发稳定性要强,某个进程挂掉不会影响其它进程。
    • 多进程可以使用cpu的多核运行,多线程可以共享全局变量。
    • 线程不能单独执行必须依附在进程里面

1、python中的多进程实现多任务

'''
多进程实现多任务一共分为三步走:
① 导入多进程模块
② 创建子进程
③ 启动进程
'''
import multiprocessing
import time

# 1、创建一个music函数
def music():
    for i in range(100):
        print('听音乐')
        time.sleep(0.2)

# 2、创建一个coding函数
def coding():
    for i in range(100):
        print('写代码')
        time.sleep(0.2)

# 3、编写Python程序的入口
if __name__ == '__main__':
    # 在Python程序的入口,会产生一个main主进程
    # 4、创建听音乐子进程与写代码的子进程
    music_process = multiprocessing.Process(target=music, name='myprocess1')
    coding_process = multiprocessing.Process(target=coding)

    # 5、启动进程
    music_process.start()
    coding_process.start()

2、python中获取进程的编号

'''
多进程实现多任务一共分为三步走:
① 导入多进程模块
② 创建子进程
③ 启动进程
'''
import multiprocessing
import time
import os

# 1、创建一个music函数
def music():
    print('music:', os.getpid())
    print('music:', multiprocessing.current_process())

    # 获取父进程ID
    print('music的父进程编号:', os.getppid())

    for i in range(5):
        print('听音乐')
        time.sleep(0.2)

# 2、创建一个coding函数
def coding():
    print('coding:', os.getpid())
    print('coding:', multiprocessing.current_process())

    # 获取父进程ID
    print('coding的父进程编号:', os.getppid())

    for i in range(5):
        print('写代码')
        time.sleep(0.2)

# 3、编写Python程序的入口
if __name__ == '__main__':
    # 在Python程序的入口,会产生一个main主进程
    # 获取主进程编号
    print('main:', os.getpid())
    # 获取主进程信息
    print('main:', multiprocessing.current_process())

    # 4、创建听音乐子进程与写代码的子进程
    music_process = multiprocessing.Process(target=music, name='myprocess1')
    coding_process = multiprocessing.Process(target=coding)

    # 5、启动进程
    music_process.start()
    coding_process.start()

3、Python中多进程实现带有参数的多任务

'''
多进程实现多任务一共分为三步走:
① 导入多进程模块
② 创建子进程
③ 启动进程
'''
import multiprocessing
import time

# 1、创建一个music函数
def music(count):
    for i in range(count):
        print('听音乐')
        time.sleep(0.2)

# 2、创建一个coding函数
def coding(count):
    for i in range(count):
        print('写代码')
        time.sleep(0.2)

# 3、编写Python程序的入口
if __name__ == '__main__':
    # 在Python程序的入口,会产生一个main主进程
    # 4、创建听音乐子进程与写代码的子进程
    music_process = multiprocessing.Process(target=music, args=(5,))
    coding_process = multiprocessing.Process(target=coding, kwargs={'count':5})

    # 5、启动进程
    music_process.start()
    coding_process.start()

4、Python中进程的注意事项——进程之间不共享全局变量

'''
多进程实现多任务一共分三步:
① 导入模块
② 创建子进程
③ 启动进程
'''
import multiprocessing
import time

# 1、定义一个全局变量
g_list = []

# 2、定义要执行的add_data函数
def add_data():
    for i in range(5):
        g_list.append(i)
        print('add_data:', i)
        time.sleep(0.2)
    print('add_data:', g_list)

# 3、定义要执行的read_data函数
def read_data():
    print('read_data:', g_list)

# 4、定义Python的入口程序
if __name__ == '__main__':
    # 创建子进程
    add_data_process = multiprocessing.Process(target=add_data)
    read_data_process = multiprocessing.Process(target=read_data)

    # 启动进程
    add_data_process.start()
    # join():主进程等待子进程执行结束,在继续执行
    add_data_process.join()
    read_data_process.start()

    # 在主进程中读取g_list
    print('main:', g_list)

5、Python中主进程会等待所有子进程结束在结束

'''
进程使用注意点:
① 进程与进程之间不共享全局变量
② 主进程会等待所有子进程结束再结束
'''
import multiprocessing
import time

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

# 定义Python入口程序
if __name__ == '__main__':
    # 创建子进程
    sub_process = multiprocessing.Process(target=task)
    # 启动子进程
    sub_process.start()

    # 主进程休眠0.5秒
    time.sleep(0.5)
    print('over')
    # 尝试退出主程序
    exit

6、Python中守护主进程与销毁子进程

'''
进程使用注意点:
① 进程与进程之间不共享全局变量
② 主进程会等待所有子进程结束再结束
'''
import multiprocessing
import time

def task():
    for i in range(10):
        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)
    print('over')
    # 解决方案二:在主程序结束之前强制销毁子进程
    sub_process.terminate()
    # 尝试退出主程序
    exit()

7、Python中多线程实现多任务

'''
Python中多线程实现多任务的三步走:
① 导入模块
② 创建子线程
③ 启动线程
'''
# 1、导入模块
import threading
import time

# 定义music()函数
def music():
    for i in range(5):
        print('听音乐')
        time.sleep(0.2)

# 定义coding()函数
def coding():
    for i in range(5):
        print('写代码')
        time.sleep(0.2)

if __name__ == '__main__':
    # 2、创建子线程
    music_thread = threading.Thread(target=music)
    coding_thread = threading.Thread(target=coding)

    # 3、启动线程
    music_thread.start()
    coding_thread.start()

8、Python中多线程实现带参数的多任务

# 1、导入模块
import threading
import time

# 定义music()函数
def music(count, times):
    for i in range(count):
        print('听音乐')
        time.sleep(times)

# 定义coding()函数
def coding(count, times):
    for i in range(count):
        print('写代码')
        time.sleep(times)

if __name__ == '__main__':
    # 2、创建子线程
    music_thread = threading.Thread(target=music, args=(5, 0.2))
    coding_thread = threading.Thread(target=coding, kwargs={'count':5, 'times':0.2})

    # 3、启动线程
    music_thread.start()
    coding_thread.start()

9、Python中线程之间的执行是没有顺序的

'''
结论:线程与线程之间的执行是没有顺序的
要用到的知识点:threading.current_thread().name => 输出当前线程的信息(名称)
'''
import threading
import time

# 创建要执行的任务
def task():
    time.sleep(1)
    # 输出线程信息
    print('当前线程:', threading.current_thread().name)


# 定义Python入口程序
if __name__ == '__main__':
    for _ in range(5):
        # 创建子线程
        sub_thread = threading.Thread(target=task)
        # 启动子线程
        sub_thread.start()

10、Python中主线程会等待子线程结束再结束

'''
结论:Python中主线程会等待所有子线程结束再结束
① 创建一个子线程,需要执行2.5s
② 创建一个主线程,需要执行1s
'''
import threading
import time

# 定义要执行的程序
def show_info():
    for i in range(5):
        print('show_info:', i)
        time.sleep(0.5)

# 定义Python入口程序
if __name__ == '__main__':
    # 本身拥有一个主线程
    # 创建子线程
    # ① 守护主线程方案一
    # sub_thread = threading.Thread(target=show_info, daemon=True)
    sub_thread = threading.Thread(target=show_info)
    sub_thread.setDaemon(True)
    # 启动子线程
    sub_thread.start()

    # 主线程休眠1s
    time.sleep(1)
    print('over')
    # 退出程序
    exit()

11、Python中线程与线程之间共享全局变量

'''
结论:线程与线程之间可以共享全局变量
'''
import threading
import time

# 定义一个全局变量
my_list = []

# 定义一个写函数,负责向my_list中写入数据
def write_data():
    for i in range(5):
        my_list.append(i)
        time.sleep(0.1)
    print('write_data:', my_list)

# 定义一个读函数,负责读取my_list中的数据
def read_data():
    print('read_data:', my_list)

if __name__ == '__main__':
    write_data_thread = threading.Thread(target=write_data)
    read_data_thread = threading.Thread(target=read_data)

    # 启动线程
    write_data_thread.start()
    # 让主线程等待子线程执行完毕后,在继续向下执行
    write_data_thread.join()
    # 从这个位置开始,真正的读取数据
    read_data_thread.start()

12、Python中线程与线程全局变量共享遇到的问题

import threading
import time

# 定义一个全局变量(数字)
g_num = 0

# 定义一个函数(循环100万次,循环累加)
def sum_num1():
    for i in range(1000000):
        global g_num
        g_num += 1
    print("sum1:", g_num)

# 定义一个函数(循环100万次,循环累加)
def sum_num2():
    for i in range(1000000):
        global g_num
        g_num += 1
    print("sum2:", g_num)

if __name__ == '__main__':
    first_thread = threading.Thread(target=sum_num1)
    second_thread = threading.Thread(target=sum_num2)

    first_thread.start()
    # 解决方案:线程同步
    first_thread.join()
    second_thread.start()