首页 > 系统相关 >进程的创建与多进程

进程的创建与多进程

时间:2022-11-18 17:26:45浏览次数:49  
标签:__ name Process 创建 print time 进程

目录

一、同步与异步

同步与异步:用来描述任务的提交方式

1.同步:提交完任务之后原地等待任务的返回结果,期间不做任何事

一个任务调起另一个任务的时候,会去等待其任务返回结果(或执行结束),然后再继续执行。

如下两图都是同步操作:
在Task A调用Task B后,Task A会等待Task B执行结束后,再继续执行。

在这里插入图片描述

2.异步:提交完任务之后不原地等待,直接去做其他事情,结果通过反馈机制获得,有结果自动通知

一个任务调起另一个任务的时候,不会去等待其返回结果(或执行结束),仍然继续执行自己的逻辑。
如下图,在Task A调用Task B后,Task A不会停止执行,Task A与Task B并行执行。

在这里插入图片描述

二、阻塞非阻塞

用来表达任务的执行状态

1.阻塞:任务处于阻塞态

是指调用结果返回之前,当前线程(进程)会被挂起
在调用的结果返回之前,当前线程(进程)不会执行其他操作。

在这里插入图片描述

2.非阻塞:任务处于就绪态、运行态

指执行一个调用,当前线程(进程)不会挂起。
当前线程(进程)如果还有其他操作,不会影响执行。

在这里插入图片描述

我们常常看到的是同步与异步、阻塞非阻塞,四者的组合

三、综合使用

1.同步阻塞

效率最低,单任务按顺序执行

2.同步非阻塞

​ 多任务,定时查看任务执行状态

3.异步阻塞

​ 单任务,自动提交任务执行状态。

4.异步非阻塞

效率最高,提交完任务之后不原地等待,直接去做其他事情,并且cpu也不会被剥夺走。多任务,自动提交任务执行状态,合理分配,最大化利用资源。

TASK A在执行过程中调起了Task B,与Task B并行执行,因此是异步。
Task A调起Task B后,并没有挂起当前线程,因此是非阻塞。

在这里插入图片描述

四、创建进程的多种方式

1.方式1:鼠标双击创建进程

​ 系统中,鼠标双击软件图标,创建进程

2.方式2:代码创建进程

​ python代码创建进程,使用multiprocessing模块中的类Process来创建进程

(1)生成类Process的对象创建进程

​ 为子进程传参需要用类Process中的arg位置传参或者kwargs关键值传参,如args=('jason',18)中,参数需要在元组中赋值给args

# 创建进程模块multiprocessing

from multiprocessing import Process
import time


def task(name,age):
    print('task is running',name)
    time.sleep(3)
    print('task is over',age)
   
if __name__ == '__main__':
    "让一个函数在同一时间执行多次"
    p1 = Process(target=task,args=('jason',18))
    p1.start()  # 异步操作:子进程 告诉操作系统创建一个新的进程,并在该进程中执行task函数
    # task()  # 同步操作
    print('主进程')  
==========运行结果===============
主进程
task is running jason
# 3s后
task is over 18

(2)编写类继承Process,来创建子进程

1.使用类继承Process类,来创建子进程

from multiprocessing import Process
import time

class MyProcess(Process):
    def run(self):
        print('run is running')
        time.sleep(3)
        print('run is over')


if __name__ == '__main__':
    obj = MyProcess()
    obj.start()
    print('主进程')
==========运行结果===============
主进程
run is running
run is over

2.传参问题利用__init__实例化方法和super派生方法传参

由于Process中已经存在名为name的属性了,当仍然想用属性name的时候,需要在super方法后赋值

class MyProcess(Process):
    def __init__(self,name,age):
        super().__init__()
        self.name = name
        self.age = age

    def run(self,):
        print('run is running',self.name)
        time.sleep(3)
        print('run is over',self.age)

if __name__ == '__main__':
    obj = MyProcess('jason',18)
    obj.start()
    print('主进程')

3.在不同的操作系统中创建进程的注意事项

由于在不同的操作系统中创建进程的底层原理不同:

在 windows 系统中,是以导入模块的形式创建进程,所以创建子进程会循环创建,直到报错。

在linux/mac 系统中, 是以拷贝代码的形式创建子进程。

image-20221118155332354

总之使用 if __name__ == '__main__':语句来创建子进程更为合适

4.进程的join方法

join方法的作用:让主进程代码等待子进程代码运行结束再执行

from multiprocessing import Process
import time


def task(name, n):
    print('%s is running' % name)
    time.sleep(n)
    print('%s is over' % name)


if __name__ == '__main__':
    p = Process(target=task, args=('jason', 1)) # 拿类产生一个对象
    p.start()  # 异步
    """主进程代码等待子进程代码运行结束再执行"""
    p.join()
    

拓展:join方法位置不同,运行时间不同

from multiprocessing import Process
import time


def task(name, n):
    print('%s is running' % name)
    time.sleep(n)
    print('%s is over' % name)


if __name__ == '__main__':
    p1 = Process(target=task, args=('jason', 1))  # 拿类产生一个对象
    p2 = Process(target=task, args=('jason', 2))
    p3 = Process(target=task, args=('jason', 3))
    """主进程代码等待子进程代码运行结束再执行"""
    print('主进程')
    start_time = time.time()
    p1.start()
    p2.start()
    p3.start()
    p1.join()
    p2.join()
    p3.join()
    print(time.time()-start_time)  
==========运行结果===============
3.058879852294922

当进程同时执行,然后在用join方法等待时,时间是3s

    "join方法位置不同,运行时间不同"
    start_time = time.time()
    p1.start()  # 对象产生进程
    p1.join()
    p2.start()
    p2.join()
    p3.start()
    p3.join()
    print(time.time() - start_time) 
==========运行结果=============== 
6.190535068511963

改变join方法的位置,则结果变成6s

五、进程间数据隔离

同一台计算机上的多个进程数据上严格意义上的物理隔离(默认情况下),也就是说默认情况下进程之间无法互相传递信息

import time
from multiprocessing import Process

name = 1000


def task():
    global name
    name = 'duoduo'
    print('子进程', name)


if __name__ == '__main__':
    p1 = Process(target=task)
    p1.start()  # 通过对象创建子进程
    time.sleep(3)  # 使主进程代码等待三秒
    print(name)  # 主进程代码打印变量名name
=======代码运行=========   
子进程 duoduo
1000

结果发现子进程运行,并不能改变主进程的变量名的值

六、ipc机制

ipc:一台计算机上的进程间通行

消息队列:存储数据的地方,公共仓库,所有人都可以存,都可以取

"当台计算机上的消息队列"
from multiprocessing import Queue
q = Queue(3)  # 括号内可以指定存储数据的个数
#  往消息队列中存放消息
q.put(1)
print(q.full())  # 判断队列是否已满返回布尔值
q.put(2)
q.put(3)
print(q.full())
# q.put(4)  # 程序等在这里了
print(q.get())
print(q.get())
print(q.empty())  # False 判断队列是否为空
print(q.get())
# print(q.get())  #  程序等在这里了长期进入io状态
print(q.get_nowait())  # 直接报错_queue.Empty

full() ``empty() 在多进程中都不能使用因为判断会失真,当某一个去判断的时候,立即有别的进程存取消息队列的数据,会改变消息队列的数据,此时的判断并不准确就会失真

image-20221118104910809

七、生产者消费者模型

主要爬虫领域

生产者:负责产生数据的人

消费者:负责处理数据的人

该模型必须在生产者和消费者之间必须要有消息队列(能存储数据的地方也可以是文件,数据库),减少了生产者和消费者的耦合

八、进程对象的多种方法

1.如何查看进程号

from multiprocessing import Process, current_process
import os


def task():
    # print(current_process())
    # print(current_process().pid)  # .pid获取当前进程的进程号
    print('子', os.getpid())
    print('子进程的主进程号', os.getppid())


if __name__ == '__main__':
    p1 = Process(target=task)
    p1.start()
    # print(current_process())
    # print(current_process().pid)
    print('主', os.getpid())  # os.getpid()获取当前进程的进程号

2.终止进程

(1)代码实现

p1.terminate() 

(2)命令行实现

3.判断进程是否存活

p1.is_alive()  光速看

4.其他

start()

九、守护进程

守护进程会随着守护的进程结束而立刻结束

当子进程是主进程的守护进程时,主进程一旦结束,那么子进程不需要手动结束也会被结束掉

from multiprocessing import Process
import time


def task(name):
    print('子进程:%s' % name)
    time.sleep(3)
    print('子进程结束')


if __name__ == '__main__':
    p = Process(target=task, args=('运行',))
    p.daemon = True  # 声明p对象生成的子进程是主进程的守护进程
    p.start()
    time.sleep(1)
    print('主进程结束')
image-20221118165522317

十、僵尸进程与孤儿进程

1.僵尸进程

进程执行完毕后并不会立刻销毁所有的数据会有一些信息短暂保留下来

​ 比如一些信息:进程号、进程执行时间、进程消耗功率等会交给父进程查看

所有的进程都会变成僵尸进程的时刻

2.孤儿进程

子进程正常运行,父进程意外死亡:操作系统针对孤儿进程会派遣

福利院管理

十一、多进程数据错乱问题

模拟抢票软件:多进程操作数据很有可能会造成数据错乱>>>:互斥锁

​ 互斥锁:将并发变成串行,牺牲了效率但是保障了数据的安全

模拟抢票软件

from multiprocessing import Process
import time
import json
import random


# 查票
def search(name):
    with open(r'data.json', 'r', encoding='utf8') as f:
        data = json.load(f)
    print('%s在查票 当前余票为:%s' % (name, data.get('ticket_num')))


# 买票
def buy(name):
    # 再次确认票
    with open(r'data.json', 'r', encoding='utf8') as f:
        data = json.load(f)
    # 模拟网络延迟
    time.sleep(random.randint(1, 3))
    # 判断是否有票 有就买
    if data.get('ticket_num') > 0:
        data['ticket_num'] -= 1
        with open(r'data.json', 'w', encoding='utf8') as f:
            json.dump(data, f)
        print('%s买票成功' % name)
    else:
        print('%s很倒霉 没有抢到票' % name)


def run(name):
    search(name)
    buy(name)


if __name__ == '__main__':
    for i in range(10):
        p = Process(target=run, args=('用户%s'%i, ))
        p.start()

此时多进程操作数据很有可能会造成数据错乱

image-20221118165818771

标签:__,name,Process,创建,print,time,进程
From: https://www.cnblogs.com/DuoDuosg/p/16903873.html

相关文章

  • 同步与异步、阻塞与非阻塞、创建进程的多种方式、进程间数据隔离、进程的join方法、IP
    目录同步与异步阻塞与非阻塞综合使用创建进程的多种方式进程间数据隔离进程的join方法IPC机制生产者消费者模型进程对象的多种方法守护进程僵尸进程与孤儿进程多进程数据错......
  • 进程
    同步与异步1同步 所谓同步就是一个任务的完成需要依赖另外一个任务时,只有等待被依赖的任务完成后,依赖的任务才能算完成,这是一种可靠的任务序列要么成功都成功,失败都......
  • 多进程的详细内容
    同步与异步用来表达任务的提交方式同步 提交完任务之后原地等待任务的返回结果,期间不做任何事情异步 提交完任务之后不原地等待任务的返回结果,直接去做其他事有结果......
  • 7. Maven创建web工程
    #命令行转到D:\Maven\maven-workspace工作空间,执行如下代码:mvnarchetype:generate-DarchetypeGroupId=org.apache.maven.archetypes-DarchetypeArtifactId=maven-arch......
  • 创建线程的三种方式,第一种继承Thread类
    【1】在学习多线程一章之前,以前的代码是单线程的吗?不是,以前也是有三个县城同时执行的。 【2】现在自己想制造多线程---》创建线程??先有线程类---》再有线程对象  ......
  • 在XP下创建自解压文件iexpress wizard(解压出的不是原文件)
    https://jingyan.baidu.com/article/f0e83a25d7fbbf22e591012b.html原因是红框内没有勾选上。选上之后就好了。   今天给大家讲在XP下创建自解压文件,XP自带的iexp......
  • Context 创建过程
    ApplicationServiceActivity里的context通过ContextImpl创建得到的,继承图:应用中的context数量:activity+service+1正确使用Context一般Context造成的内存泄漏,几......
  • 65:推导式创建序列_列表推导式_字典推导式_集合推导式_生成器推导式
    ###推导式创建序列推导式是从一个或者多个迭代器快速创建序列的一种方法。它可以将循环和条件判断结合,从而避免冗长的代码。推导式是典型的Python风格,会使用它代表你已......
  • 02_虚拟DOM的两种创建方式
      一、1_使用jsx创建虚拟DOM<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><title>1_使用jsx创建虚拟DOM</title></head><body><......
  • Java-14流Stream【创建一个简易for循环工具】
    Java-14流Stream构造简易的循环取代forIntStream类提供了一个range()方法,可以生成一个流————由int值组成的序列importstaticjava.util.stream.IntStream.*;/**......