Python本人自学笔记(17) 进程与线程

了解什么是程序与进程

掌握创建进程的方式

掌握进程之间的通信

了解进程与线程的概述

掌握创建线程的方式

掌握线程之间的通信方式

掌握生产者与消费者模式

创建进程的方式

方法 / 属性名称功能描述
name当前进程实力别名,默认为Process-N
pid当前进程对象的PID值
is_alive()进程是否执行完,没执行完结果为True,否则为False
join(timeout)等待结束或等待timeout秒
start()启动进程
run()如果没有指定target参数,则启动进程后,会调用父类中的run方法
terminate()强制终止进程

第一种创建进程

语法结构:

        Process(group=Npne,target,name,args,kwargs)

参数说明:

(1)group:表示分组,实际上不使用,默认值为None即可

(2)target:表示子进程要执行的任务,支持函数名

(3)name:表示子进程的名称

(4)args:表示调用函数的参数位置,以元组的形式进行传递

(5)kwargs:表示调用函数的关键字参数,以字典的形式进行

from multiprocessing import Process
import os,time
#函数中的代码是子进程要执行的代码
def test():
    print(f'我是子进程,我的PIP是:{os.getpid()},我的父进程是:{os.getppid()}')
    time.sleep(1)

if __name__ == '__main__':
    print('主进程开始执行')
    lst=[]
    # 创建5个进程
    for i in range(5):
        # 创建子进程
        p = Process(target=test)
        # 将启动的进程添加到列表中
        p.start()
        #启动中的进程添加到列表中
        lst.append(p)
        # 遍历列表中的子进程
    for item in lst:
        item.join()#阻塞主进程
    print('主进程结束')

第二种创建进程

语法结构:

class 子进程(Process):

        pass
from multiprocessing import Process
import os,time
#自定义一个类
class SubProcess(Process):
    def __init__(self,name):
        super().__init__()
        self.name=name
    def run(self):
        print(f'子进程的名称{self.name},PID:{os.getpid()},父进程的PID:{os.getppid()}')

if __name__ == '__main__':
    print('父进程开始执行')
    lst=[]
    for i in range(1,6):
        p1=SubProcess(f'进程:{i}')
        #启动进程
        p1.start()
        lst.append(p1)

    for item in lst:
        item.join()
    print('父进程执行结束')

Pool 进程池

进程池的原理是创建一个进程池,并设置进程池中最大的进程数量。假设进程池中最大的进程数为3,现在有10个任务需要执行,那么进程池一次可以执行3个任务,4次即可完成全部任务的执行。

创建进程池的语法结构:

        进程池对象=Pool(N)

方法名功能描述
apply_async(func,args,kwargs)使用非阻塞方式调用函数func
apply(func,args,kwargs)使用阻塞方式调用函数func
close()关闭进程池,不再接收新任务
terminate()不管任务是否完成,立即终止
join()阻塞主进程,必须在terminate()或close()之后使用

进程之间的通信

进程之间可以通过队列(Queue)进行通信,队列是一种先进先出(First In First Out)的数据结构。

方法名称功能描述
qsize()获取当前队列包含的信息数量
empty()

判断队列是否为空,为空结果为True,否则为False

full()

判断队列是否满了,满结果为True,否则为False

get(block_True)

获取队列中的一条消息,然后从队列中移除,block默认值为True

get_nowait()相当于get(block_False),消息队列为空时抛出异常
put(item,block-True)将item消息放入队列,block默认为True 消息队列满时会排队等待直到有空位时加入
put_nowait(item)相当于put(item,block=False) 消息队列满时报错

队列示例:
 

from multiprocessing import Queue,Process
import time
a=100
def write_msg(q):# q是队列
    global a
    if not q.full():
        for i in range(6):
            a-=10
            q.put(a)# 入队
            print('a入队时的值:',a)

# 出队
def read_msg(q):
    time.sleep(1)
    if not q.empty():
        print('出队时a的值:',q.get())

if __name__ == '__main__':
    print('父进程开始执行')
    q=Queue()# 由父进程创建队列,没有指定参数,说明可接收消息的个数没有上限
    # 创建两个子进程
    p1=Process(target=write_msg,args=(q,))
    p2=Process(target=read_msg,args=(q,))
    # 启动两个子进程
    p1.start()
    p2.start()
    # 等待进程执行结束
    p1.join()
    p2.join()
    print('父进程执行完毕')

创建线程的方式

函数式创建线程

语法结构:
        t=Thread(group,target,name,args,kwargs)

参数说明:

(1)group:创建线程对象的进程组

(2)target:创建的线程对象所要执行的目的函数

(3)name:创建线程对象的名称,默认为“Thread-n”

(4)args:用元组以位置参数的形式传入target对应函数的参数

(5)kwargs:用字典以关键字参数的形式传入target对应函数的参数

from threading import Thread
import threading
import time

def text():
    for i in range(3):
        time.sleep(3)
        print(f'线程:{threading.current_thread().name}正在执行')

if __name__ == '__main__':
    start = time.time()
    print('主线程开始执行')
# 创建线程
    lst=[Thread(target=text) for i in range(2)]

    for item in lst:# item的数据类型是Thread类型
        item.start()
    for item in lst:
        item.join()
    print(f'一共耗时:{time.time() - start}')

使用Thread子类创建线程

操作步骤:

(1)自定义类继承 threading 模块下的 Thread 类

(2)实现 run 方法

import threading
from threading import Thread
import time

class SubThread(Thread):
    def run(self):
        for i in range(3):
            time.sleep(1)
            print(f'线程:{threading.current_thread().name}正在执行{i}')

if __name__ == '__main__':
    print('主线程开始执行')
    lst = [SubThread() for i in range(2)]
    for i in lst:
        i.start()
    for i in lst:
        i.join()
    print('主线程运行完毕')

线程操作共享数据的安全性问题

举例:

import threading
from threading import Thread
import time

ticket=50# 代表有40张票
def sale_ticket():
    global ticket
    # 每个排队窗口有100人
    for i in range(100):# 每个线程要执行100次循环
        if ticket>0:
            print(f'{threading.current_thread().name}正在出售第{ticket}张票')
            ticket-=1
        time.sleep(1)

if __name__ == '__main__':
    for i in range(3):# 创建三个线程,代表3个窗口
        t=Thread(target=sale_ticket)
        t.start()

 以上代码运行时会出先多个进程抢一个目标的情况(不安全)

Lock锁

当一个线程操作一个共享数据时,会给共享数据上锁,其他线程到达时只能等待。之后共享资源的锁被打开时才能被访问

导入 Lock ,创建锁对象(对象名=Lock()),在合适的位置上锁(对象名.acquire()),在合适的位置释放锁(对象名.release())

import threading
from threading import Thread, Lock
import time

ticket = 50  # 代表有40张票
lock_obj = Lock()  # 创建锁对象


def sale_ticket():
    global ticket
    # 每个排队窗口有100人
    for i in range(100):  # 每个线程要执行100次循环
        lock_obj.acquire()  # 上锁
        if ticket > 0:
            print(f'{threading.current_thread().name}正在出售第{ticket}张票')
            ticket -= 1
        time.sleep(0.1)
        lock_obj.release()  # 释放锁


if __name__ == '__main__':
    for i in range(3):  # 创建三个线程,代表3个窗口
        t = Thread(target=sale_ticket)
        t.start()

生产者与消费者模式

生产者与消费者模式是线程模型中的经典问题,与编程语言无关。当程序中出现了明确的两类任务,一个任务负责生产数据,一个任务负责处理生产的数据时就可以使用该模式。

Python中的内置模块queue中的Queue类

方法名称功能描述
put(item)向队列中放置数据,如果队列为满,则阻塞
get()从队列中取走数据,如果队列为空,则阻塞
join()如果队列不为空,则等待队列变为空
task_done()消费者熊队列中取走一项数据,当队列变为空时,唤醒调用join()的线程
from queue import Queue
from threading import Thread
import time

class Producer(Thread):
    def __init__(self,name,queue):
        Thread.__init__(self,name=name)
        self.queue = queue
    def run(self):
        for i in range(1,6):
            print(f'{self.name} 将产品{i}放入队列')
            self.queue.put(i)
            time.sleep(1)
        print('生产者完成了所有数据的存放')

class Consumer(Thread):
    def __init__(self,name,queue):
        Thread.__init__(self,name=name)
        self.queue = queue
    def run(self):
        for i in range(5):
            value = self.queue.get()
            print(f'消费者线程{self.name}取出了{value}')
            time.sleep(1)
        print('------消费者线程完成了所有数据的取出------')

if __name__ == '__main__':
    queue=Queue()
    p=Producer('Producer',queue)
    c=Consumer('Consumer',queue)
    p.start()
    c.start()
    p.join()
    c.join()
    print('主线程执行结束')
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值