第13章 1 进程和线程

这篇具有很好参考价值的文章主要介绍了第13章 1 进程和线程。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

程序和进程的概念 p173

进程是运行态的程序

函数式创建子进程

fork可以用于unix类的操作系统:linux,macos
但是在windows系统中,只能使用Process,详见下


第一种创建进程的语法结构:

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

参数说明:
1、group:表示分组,实际上不使用,值默认为None即可;可不写
2、target:表示子进程要执行的任务,支持函数名
3、name:表示子进程的名称;可不写
4、args:表示调用函数的位置参数,以元组的形式进行传递;有就写
5、kwargs:表示调用函数的关键字参数,以字典的形式进行传递;有就写

代码实例1:

import multiprocessing
import os
import time

def test():
    print(f'我是子进程,我的PID是:{os.getpid()},我的父进程是{os.getppid()}')
    time.sleep(1)

if __name__=='__main__':
    print('主进程开始执行')
    lst=[]

    # 创建五个子进程
    for i in range(5):
        # 创建单个子进程
        p=multiprocessing.Process(target=test) # 返回值类型为:<class 'multiprocessing.context.Process'>
        print(type(p))
        # 启动子进程
        p.start()
        # 启动中的进程加到列表中
        lst.append(p)

    print('主进程执行结束')

上面的运行结果是主进程先结束,子进程在逐个结束
若要求所有子进程中的代码执行结束,主进程在结束,可以使用join()方法,阻塞,见下面:

import multiprocessing
import os
import time

def test():
    print(f'我是子进程,我的PID是:{os.getpid()},我的父进程是{os.getppid()}')
    time.sleep(1)

if __name__=='__main__':
    print('主进程开始执行')
    lst=[]

    # 创建五个子进程
    for i in range(5):
        # 创建单个子进程
        p=multiprocessing.Process(target=test) # 返回值类型为:<class 'multiprocessing.context.Process'>
        # 启动子进程
        p.start()
        # 启动中的进程加到列表中
        lst.append(p)

    for item in lst:
        item.join()  # 阻塞主进程

    print('主进程执行结束')

Process类常用的属性和方法1 p175

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

代码实例:

import os,multiprocessing,time

def sub_process(name):
    print(f'子进程pid:{os.getpid()},父进程的pid:{os.getppid()},入参name={name}')
    time.sleep(1)

def sub_process2(name):
    print(f'子进程pid:{os.getpid()},父进程的pid:{os.getppid()},入参name={name}')
    time.sleep(1)

if __name__ == '__main__': # 直接写main
    # 主进程
    print('父进程开始执行')
    for i in range(5):
        # 创建第一个子进程
        p1=multiprocessing.Process(target=sub_process,args=('ysj',))
        # 创建第二个子进程
        p2=multiprocessing.Process(target=sub_process2,args=(18,))
        # 调用Process类的start方法启动子进程
        p1.start()
        p2.start()
        # 调用进程对象的类属性
        print(p1.name,'是否执行完毕:',not p1.is_alive())
        print(p2.name, '是否执行完毕:', not p2.is_alive())

        p1.join() # 主程序阻塞等待p1结束
        p2.join() # 主程序阻塞等待p2结束

    print('父进程执行结束')

Process类中常用的属性和方法2 p176

代码实例1:

import os,multiprocessing,time

if __name__ == '__main__': # 直接写main
    # 主进程
    print('父进程开始执行')
    for i in range(5):
        # 创建第一个子进程
        p1=multiprocessing.Process() # 没有给定taget参数,会调用执行Process类中的run方法
        # 创建第二个子进程
        p2=multiprocessing.Process()

        p1.start() # 调用Process类中的run方法去执行
        p2.start()

    print('父进程执行结束')

代码实例2:

import os,multiprocessing,time

def sub_process(name):
    print(f'子进程pid:{os.getpid()},父进程的pid:{os.getppid()},入参name={name}')
    time.sleep(1)

def sub_process2(name):
    print(f'子进程pid:{os.getpid()},父进程的pid:{os.getppid()},入参name={name}')
    time.sleep(1)

if __name__ == '__main__': # 直接写main
    # 主进程
    print('父进程开始执行')
    for i in range(5):
        # 创建第一个子进程
        p1=multiprocessing.Process(target=sub_process,args=('ysj',)) # 没有给定taget参数,会调用执行Process类中的run方法
        # 创建第二个子进程
        p2=multiprocessing.Process(target=sub_process2,args=(18,))

        p1.start()
        p2.start()

        # 强制终止进程
        p1.terminate()
        p2.terminate()

    print('父进程执行结束')

继承式创建子进程 p177

第二种创建进程的语法结构:

class 子进程(Process): # 继承Process类,然后去重写run方法
	pass

代码实例:

import multiprocessing,time,os

# 自定义一个类
class SubProcess(multiprocessing.Process): # 继承Process类
    # 编写一个初始化方法
    def __init__(self,name):
        # 调用父类的初始化方法
        super().__init__()
        self.name=name

    # 重写父类的run方法
    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() # 没有参数会调用run方法
        lst.append(p1)

    # 阻塞主进程,等待子进程执行完毕
    for item in lst:
        item.join()

    print('父进程执行结束')

进程池的使用 p178

若要创建、管理的进程有上百个,创建、销毁线程要消耗大量的时间。进程池可以解决这个问题

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

创建进程池的语法结构:

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

代码实例:非阻塞运行进程池

import multiprocessing,os,time

# 编写任务
def task(name):
    print(f'子进程的PID:{os.getpid()},父进程的PID:{os.getppid()},执行的任务:{name}')
    time.sleep(1)

if __name__ == '__main__':
    # 主进程
    start=time.time() # 返回时间戳,单位是秒
    print(start,':父进程开始执行')
    # 创建进程池
    p=multiprocessing.Pool(3)
    # 创建任务
    for i in range(10):
        # 以非阻塞方式
        p.apply_async(func=task,args=(i,))

    # 关闭进程池不再接收新任务
    p.close()
    # 阻塞主进程等待子进程执行完毕
    p.join()

    print(time.time()-start)

    print('父进程执行结束')

代码实例:阻塞运行进程池

import multiprocessing,os,time

# 编写任务
def task(name):
    print(f'子进程的PID:{os.getpid()},父进程的PID:{os.getppid()},执行的任务:{name}')
    time.sleep(1)

if __name__ == '__main__':
    # 主进程
    start=time.time() # 返回时间戳,单位是秒
    print(start,':父进程开始执行')
    # 创建进程池
    p=multiprocessing.Pool(3)
    # 创建任务
    for i in range(10):
        # 非阻塞方式
        p.apply(func=task,args=(i,))

    # 关闭进程池不再接收新任务
    p.close()
    # 阻塞主进程等待子进程执行完毕
    p.join()

    print(time.time()-start) # 非阻塞用了4秒多,阻塞方式用了10秒多

    print('父进程执行结束')

并发和并行 p179

并发:
是指两个或多个事件在 同一时间间隔 发生,多个任务被交替轮换着执行,比如A事件在吃苹果,在吃苹果的过程中有快递员敲门让你收下快递,收快递就是B事件,name收完快递继续吃没吃完的苹果。就是并发。

并行:
指两个或多个事件在同一时刻发生,多个任务在同一时刻在多个处理器上同时执行。比如A事件是泡脚,B事件是打电话,C事件是记录电话内容,这三件事则可以在同一时刻发生,这就是并行。

进程之间数据是否共享 p180

Python当中的并行对应多进程

代码实例:

import multiprocessing,os

a=100


def add():
    print('子进程1开始执行')
    global a
    a+=30
    print('a=',a)
    print('子进程1执行完毕')

def sub():
    print('子进程2开始执行')
    global a
    a-=50
    print('a=',a)
    print('子进程2执行完毕')

if __name__ == '__main__':
    # 父进程
    print('父进程开始执行')
    # 创建加的子进程
    p1=multiprocessing.Process(target=add)
    # 创建减的子进程
    p2=multiprocessing.Process(target=sub())
    # 启动子进程
    p1.start()
    p2.start()
    # 主进程阻塞,等待子进程执行完成
    p1.join()
    p2.join()

    print('父进程结束执行')

发现结果分别为 130和50,由此发现多进程之间的数据不是共享的,子进程1中有一份a,子进程2中还有另一份a

如何解决进程之间的数据共享,见下一节

队列的基本使用 p180

进程之间可以通过队列(queue)进行通信
队列是一种先进先出的数据结构


创建队列的语法结构:

队列对象=Queue(N)

方法名称 功能描述
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)

代码实例:

import multiprocessing

if __name__ == '__main__':
    # 创建一个队列
    q=multiprocessing.Queue(3) # 这个队列最多可以接收3条信息

    print('队列是否有空?',q.empty())
    print('队列是否为满?',q.full())
    print('队列中的消息数?',q.qsize())

    print('-'*88)

    # 向队列中添加信息
    q.put('hello')
    q.put('world')


    print('队列是否有空?', q.empty())
    print('队列是否为满?', q.full())
    print('队列中的消息数?', q.qsize())

    print('-'*88)

    q.put('11111111')

    print('队列是否有空?', q.empty())
    print('队列是否为满?', q.full())
    print('队列中的消息数?', q.qsize())

    print('-' * 88)

    print(q.get())
    print('队列中的消息数?', q.qsize())

    print(q.get())
    print(q.get())
    print('队列中的消息数?', q.qsize())

'''
队列的遍历:
for i in range(q.qsize()):
	q.get_nowait()
'''

使用队列实现进程之间的通信 p182

代码实例1:

import multiprocessing

if __name__ == '__main__':
    q=multiprocessing.Queue(3)
    # 向队列中添加元素
    q.put('hello')
    q.put('world')
    q.put('python')

    q.put('html',block=True,timeout=2) # 阻塞等待,最多两秒,若到了两秒会报错返回

代码实例2:

import multiprocessing,time

a=100

# 入队
def write_msg(q):
    global a # 要在函数内使用全局变量,一定要先用此方法声明
    if not q.full():
        for i in range(6):
            a-=10
            q.put(a)
            print(f'a入队时的值:{a}')

# 出队
def read_msg(q):
    time.sleep(1)
    while q.qsize()>0:
        print(f'出队时a的值:{q.get()}')

if __name__ == '__main__':
    print('父进程开始执行')
    q=multiprocessing.Queue() # 不写参数表示队列接收的消息个数是没有上限的
    # 创建两个子进程
    p1=multiprocessing.Process(target=write_msg,args=(q,))
    p2=multiprocessing.Process(target=read_msg, args=(q,))
    # 启动两个子进程
    p1.start()
    p2.start()
    # 等待写的进程结束,再去执行主进程
    p1.join()
    p2.join()
    print('父进程执行完毕')

函数式创建线程 p183

线程是cpu可调度的最小单位,被包含在进程中,是进程中实际的运作单位。

一个进程可以拥有N多个线程并发执行,而每个线程并行执行不同的任务。

创建线程的方法有两种:函数式创建线程和继承式创建线程

函数式创建线程的语法结构:

t=Thread(group,target,name,args,kwargs)

参数说明:
1、group:创建线程对象的进程组
2、target:创建线程对象所要执行的目标函数
3、name:创建线程对象的名称,默认为 Thread-n
4、args:用元组以位置参数的形式传入target对应函数的参数
5、kwargs:用字典以关键字参数的形式传入target对应函数的参数

代码实例:

import threading,time

# 编写线程执行函数
def test():
    for i in range(3):
        time.sleep(1)
        print(f'线程名:{threading.current_thread().name},正在执行{i}') # 获取当前的线程对象threading.current_thread()

if __name__ == '__main__':
    start=time.time()
    print('主线程开始执行')

    # 线程
    lst=[threading.Thread(target=test) for i in range(2)]

    for item in lst: # item的数据类型就是Thread类型
        # 启动线程
        item.start()

    for item in lst:
        item.join()

    print('主线程执行完毕')
    print(f'一共耗时{time.time()-start}秒')

# 一共有一个进程,三个线程(一个主线程,两个子线程)

继承式创建线程 p184

使用Thread子类创建线程的操作步骤:
1、自定义类继承threading模块下的Thread类
2、实现run方法

代码实例:

import threading,time

class SubThread(threading.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 item in lst:
        item.start()

    for item in lst:
        item.join()

    print('主线程执行完毕')

线程之间数据共享 p185

线程之间的数据可以共享吗?

import threading

a=100

def add():
    print('加线程开始执行')
    global a
    a+=30
    print(f'a的值为{a}')
    print('加线程执行完成')

def sub():
    print('减线程开始执行')
    global a
    a-=50
    print(f'a的值为{a}')
    print('减线程执行完成')

if __name__ == '__main__':
    print('主线程开始执行')
    print(f'全局变量a的值为{a}')
    add=threading.Thread(target=add)
    sub=threading.Thread(target=sub)

    add.start() # a=130
    sub.start() # a=80

    add.join()
    sub.join()

    print('主线程执行完成')

由此可以得到结论:线程之间是可以共享数据的,进程之间不可以共享数据文章来源地址https://www.toymoban.com/news/detail-804341.html

到了这里,关于第13章 1 进程和线程的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Python小姿势 - 线程和进程:

    线程和进程: Python里面线程是真正的并行执行,进程是可以并行执行的。 所谓进程,就是操作系统中执行一个程序的独立单元,它是系统进行资源分配和调度的基本单位。一个进程可以创建和撤销另一个进程,同一个进程内可以并发执行多个不同的子程序。 所谓线程,是进

    2024年02月01日
    浏览(44)
  • Python多任务教程:进程、线程、协程

    进程是一个具有一定独立功能的程序在一个数据集上的一次动态执行的过程,是操作系统进行资源分配和调度的一个独立单位,是应用程序运行的载体。进程是一种抽象的概念,从来没有统一的标准定义。进程一般由程序、数据集合和进程控制块三部分组成。程序用于描述进

    2024年02月12日
    浏览(39)
  • python多进程与多线程

    1.1 GIL 全局解释器锁 其他语言,CPU是多核时是支持多个线程同时执行。但在Python中,无论是单核还是多核,同时只能由一个线程在执行。其根源是GIL的存在。GIL的全称是Global Interpreter Lock(全局解释器锁),来源是Python设计之初的考虑,为了数据安全所做的决定。某个线程想要执

    2024年02月05日
    浏览(39)
  • 8.0 Python 使用进程与线程

    python 进程与线程是并发编程的两种常见方式。进程是操作系统中的一个基本概念,表示程序在操作系统中的一次执行过程,拥有独立的地址空间、资源、优先级等属性。线程是进程中的一条执行路径,可以看做是轻量级的进程,与同一个进程中的其他线程共享相同的地址空间

    2024年02月13日
    浏览(41)
  • 【Python】多进程线程与CPU核数

    多进程数量设置为CPU核数,或者略小于CPU核数; 多线程数量,如果是CPU密集任务设为1;如果是IO密集设为合理的值; IO密集型:系统运作,大部分的状况是CPU 在等I/O (硬盘/内存)的读/写。 计算密集型:大部份时间用来做计算、逻辑判断等CPU 动作的程序称之CPU 密集型。 对

    2024年01月16日
    浏览(35)
  • Python中的并发编程:多线程与多进程的比较【第124篇—多线程与多进程的比较】

    在Python编程领域中,处理并发任务是提高程序性能的关键之一。本文将探讨Python中两种常见的并发编程方式:多线程和多进程,并比较它们的优劣之处。通过代码实例和详细的解析,我们将深入了解这两种方法的适用场景和潜在问题。 多线程是一种轻量级的并发处理方式,适

    2024年03月14日
    浏览(94)
  • [Python系列] 线程、协程、进程和分布式

            我们在写脚本的时候,经常是单线程跑完了全部,毕竟自顶向下按照我们约定的方法运行下去是最规范的。但是很多时候,比如说合法地爬取一些网页信息,图片和资料啊,或者说一些合法的网络请求,读写文件之类的。如果还是单线程地one by one,那么将会影响我们

    2024年02月16日
    浏览(36)
  • 一文掌握Python多线程与多进程

    并发是今天计算机编程中的一项重要能力,尤其是在面对需要大量计算或I/O操作的任务时。Python 提供了多种并发的处理方式,本篇文章将深入探讨其中的两种:多线程与多进程,解析其使用场景、优点、缺点,并结合代码例子深入解读。 Python中的线程是利用 threading 模块实现

    2024年02月09日
    浏览(42)
  • Python中进程和线程到底有什么区别?

    python 安装包+资料:点击此处跳转文末名片获取 一、进程和线程的关系 线程与进程的区别可以归纳为以下4点: 地址空间和其它资源(如打开文件) :进程间相互独立,同一进程的各线程间共享。某进程内的线程在其它进程不可见。 通信 :进程间通信IPC,线程间可以直接读写

    2023年04月08日
    浏览(40)
  • 【Python爬虫与数据分析】进程、线程、协程

    目录 一、概述 二、进程的创建 三、线程的创建 四、协程的创建 五、全局变量的共享问题 六、消息队列与互斥锁 七、池化技术 进程是系统分配资源的基本单位,线程是CPU调度的基本单位。 一个进程可包含多个线程,一个线程可包含多个协程,协程就是最小的任务执行单位

    2024年02月13日
    浏览(39)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包