Fork me on github

Python之进程与线程

进程与多线程

1. 进程

1.1 什么是进程

  • 进程是操作系统分配内存资源的最小单位
  • 一个进程之内会默认有一个线程
  • 进程是Python程序中执行多任务的一种方式

在这里插入图片描述

1.2 多进程的使用

  • 进程创建的三步:
    • 导入包 import multiprocessing
    • 创建进程
    • 启动进程 start

在这里插入图片描述

import multiprocessing
import time

def dance():
    for item in range(1, 5):
        print("跳舞...")
        time.sleep(0.2)
        pass
    pass

def sing():
    for item in range(1, 5):
        print("唱歌...")
        time.sleep(0.2)
        pass
    pass


if __name__ == "__main__":
    # group 进程组,默认是None,一般不会使用
    # target 所需要执行的任务
    # name 进程名,默认是process-1,2,.....
    # args 参数(元组类型)
    dance_process = multiprocessing.Process(target=dance)
    dance_process.start()
    sing()

在这里插入图片描述

import multiprocessing
import time

def dance():
    for item in range(1, 5):
        print("跳舞...")
        time.sleep(0.2)
        pass
    pass

def sing():
    for item in range(1, 5):
        print("唱歌...")
        time.sleep(0.2)
        pass
    pass


if __name__ == "__main__":
    dance_process = multiprocessing.Process(target=dance)
    sing_process = multiprocessing.Process(target=sing)
    dance_process.start()
    sing_process.start()

1.3 获取进程的编号

  • 获取主进程和子进程编号os.getpid()
  • 在子进程内获取他的父进程编号os.getppid()
  • 通过进程编号停止进程os.kill(process_id, 9)
import multiprocessing
import time
import os

def dance():
    dance_process_id = os.getpid()
    print("dance进程编号: ", dance_process_id, multiprocessing.current_process)
    dance_process_parent_id = os.getppid()
    print("dance父进程编号: ", dance_process_parent_id)
    for item in range(1, 5):
        print("跳舞...")
        time.sleep(0.2)
        # 9 表示强行停止该进程
        os.kill(dance_process_id, 9)
        pass
    pass

def sing():
    sing_process_id = os.getpid()
    print("sing进程编号: ", sing_process_id, multiprocessing.current_process)
    for item in range(1, 5):
        print("唱歌...")
        time.sleep(0.2)
        pass
    pass

if __name__ == "__main__":
    dance_process = multiprocessing.Process(target=dance)
    sing_process = multiprocessing.Process(target=sing)
    dance_process.start()
    sing_process.start()
    main_processs_id = os.getpid()
    print("主进程编号: ", main_processs_id, multiprocessing.current_process)

1.3 进程执行带有参数的执行方式

  • 以元组的方式传递(args
  • 以字典的方式传递(kwargs
  • 以元组和字典的方式传递(args, kwargs
import multiprocessing

def show_info(name, age):
    print(name, age)
    pass


if __name__ == "__main__":
    # 方式一
    print_process = multiprocessing.Process(target=show_info, args=("一之濑", 16))
    print_process.start()
    # 方式二
    print_process2 = multiprocessing.Process(target=show_info, kwargs={"name": "周雪", "age": 18})
    print_process2.start()
    # 方式三
    print_process3 = multiprocessing.Process(target=show_info, args=("付佳慧",), kwargs={"age": 19})
    print_process3.start()

1.4 进程之间不共享资源

  • 进程之间不共享资源的原因
  • if __name__ == __main__:的两个作用

在这里插入图片描述

import multiprocessing
import time
g_list = list()

def add_list():
    for i in range(1, 5):
        g_list.append(i)
        time.sleep(0.2)
        print(i)
        pass
    pass


def read_list():
    print(g_list)

if __name__ == '__main__':
    add_process = multiprocessing.Process(target=add_list)
    read_process = multiprocessing.Process(target=read_list)
    add_process.start()
    # join 是当前进程下(主进程),只有当子进程执行完成之后,才得以往下执行
    add_process.join()
    read_process.start()
    print(g_list)


if __name__ == __main__:的两个作用

  • 避免外部导包执行该区域的代码
  • 避免windows下,进程产生递归

1.5 主进程会等待子进程执行完才销毁

  • 如果子进程是一个死循环会怎么办?
    • 主进程销毁之前,销毁子进程
    • 让子进程守护主进程,主进程销毁子进程销毁,子进程会依赖于子进程。
import multiprocessing
import time

g_list = list()

def rask():
    for i in range(1, 10):
        g_list.append(i)
        time.sleep(0.2)
        print(i)
        pass
    pass


if __name__ == '__main__':
    rask_process = multiprocessing.Process(target=rask)
    # 方式一:
    # rask_process.daemon = True
    rask_process.start()
    time.sleep(1)
    # 方式二;
    rask_process.terminate()
    print("over")

2. 线程

2.1 什么是线程

  • 线程是操作系统调度运算的最小单位,是进程的实际运作单位。
  • 线程自己不拥有系统资源
  • 同一个进程下面的线程能够共享进程所拥有的的资源
  • 一个线程能够创建或撤销另外一个进程。
  • 同一个进程的多个线程能够并发执行
  • 线程是执行多任务的一种方式

2.2 线程的使用

  • 导入threading模块
  • 创建子线程
  • 启动子线程
import threading
import time

def sing():
    for i in range(3):
        print("sing...")
        time.sleep(0.2)
    pass

def dance():
    for i in range(3):
        print("dance...")
        time.sleep(0.2)
    pass


if __name__ == '__main__':
    sing_thread = threading.Thread(target=sing)
    sing_thread.start()
    dance_thread = threading.Thread(target=dance)
    dance_thread.start()

2.3 使用线程执行带有参数的执行方式

  • args
  • kwargs

2.4 线程的注意事项

线程之间的执行顺序是无序的

import threading
import time


def rask():
    time.sleep(1)
    print(threading.current_thread())

    pass


if __name__ == '__main__':
    for item in range(5):
        rask_threading = threading.Thread(target=rask)
        rask_threading.start()
        pass

执行结果

<Thread(Thread-2, started 18756)>
<Thread(Thread-1, started 20816)>
<Thread(Thread-4, started 18496)>
<Thread(Thread-3, started 7556)>
<Thread(Thread-5, started 20920)>

主线程会等待子线程执行完结果

  • 如果子线程是一个死循环的话?
  • 让子线程守护主线程demaon(就可以结束死循环)
import threading
import time

def rask():
    while True:
        print("正在执行中.....")
        time.sleep(0.2)
        pass
    pass

if __name__ == '__main__':
    # 方法一:
    # rask_threading = threading.Thread(target=rask, daemon=True)
    rask_threading = threading.Thread(target=rask)
    # 方法二
    rask_threading.setDaemon(True)
    rask_threading.start()
    time.sleep(1)
    print("over")

线程之间是可以共享数据的

import threading
import time
g_list = list()

def add_list():
    for item in range(5):
        g_list.append(item)
        print(item)
        time.sleep(0.2)
        pass
    pass

def read_list():
    print(g_list)
    pass

if __name__ == '__main__':
    add_thread = threading.Thread(target=add_list)
    add_thread.start()
    # 当前进程等待add_thread进程执行完之后,才能够往下执行
    add_thread.join()
    read_thread = threading.Thread(target=read_list)
    read_thread.start()

线程之间共享全局变量出现错误的情况

  • 两个线程同时访问全局变量

在这里插入图片描述

import threading
import time
num = 0

def first():

    for item in range(100000):
        global num
        num = num + 1
        pass
    print(num)
    pass

def second():

    for item in range(100000):
        global num
        num = num + 1
        pass
    print(num)
    pass


if __name__ == '__main__':
    first_thread = threading.Thread(target=first)
    second_thread = threading.Thread(target=second)
    first_thread.start()
    # 解决方法
    first_thread.join()
    second_thread.start()

2.5 互斥锁

  • lock = threading.Lock()
  • 上锁lock.acquire()
  • 释放锁lock.release
import threading
import time
num = 0
lock = threading.Lock()

def first():
    lock.acquire()
    for item in range(100000):
        global num
        num = num + 1
        pass
    lock.release()
    print("rask1:", num)
    pass

def second():
    lock.acquire()
    for item in range(100000):
        global num
        num = num + 1
        pass
    lock.release()
    print("rask2:", num)
    pass

if __name__ == '__main__':
    first_thread = threading.Thread(target=first)
    second_thread = threading.Thread(target=second)
    first_thread.start()
    second_thread.start()

第一次写博客,后续会慢慢更新

posted @ 2022-01-23 11:59  不想努力的小龙  阅读(265)  评论(0编辑  收藏  举报