python进程

Posted Hello World

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python进程相关的知识,希望对你有一定的参考价值。

1.什么是进程

进程:正在进行的过程或者一个任务,是系统进行资源调度和分配的基本单元。进程是操作系统中最基本、最重要的概念。是多道程序系统出现后,为了刻画系统内部出现的动态情况,描述系统内部各道程序的活动规律引进的一个抽象的概念,所有多道程序设计操作系统都建立在进程的基础上。

进程与程序的区别:程序仅仅是一堆代码,而进程表示程序的运行过程。同一个程序被运行多次表示开启了多个进程。

2.进程的并行与并发

  • 并行:指多个进程同时执行,即在同一时间段上有多个进程在运行,实现并行前提是计算机为多核。
  • 并发:属于为并行,是在单核的条件下实现并发,多个进程交替运行。

            

 

3.同步异步阻塞非阻塞

  • 同步:一个任务的完成需要依赖另外一个任务时,只有等待被依赖的任务完成后,依赖的任务才能算完成,这是一种可靠的任务序列。要么成功都成功,失败都失败,两个任务的状态可以保持一致。
  • 异步:不需要等待被依赖的任务完成,只是通知被依赖的任务要完成什么工作,依赖的任务也立即执行,只要自己完成了整个任务就算完成了。至于被依赖的任务最终是否真正完成,依赖它的任务无法确定,所以它是不可靠的任务序列。

在程序运行的过程中,由于被操作系统的调度算法控制,程序会进入:就绪、运行和阻塞三个阶段

就绪:当进程已经分配到除CPU外的所有必要资源,子要获得处理机就可以立即执行。

执行/运行:程序获得处理机,其程序正在运行。

阻塞:正在执行的进程,由于等待某个事件发生而无法执行时,便放弃处理机而处于阻塞状态。引起阻塞原因包括(等待I/O完成、申请缓冲不能满足、等待信号等)。

 

4.进程的创建方式

Python中创建进程主要应用Process类:

Process(group , target , name , args , kwargs),由该类实例化得到的对象,表示一个子进程中的任务(尚未启动) 强调:

  • 参数介绍:
  • group参数未使用,值始终为None
  • target表示调用对象,即子进程要执行的任务
  • args表示调用对象的位置参数元组,args=(1,2,\'kkk\',)
  • kwargs表示调用对象的字典,kwargs={\'name\':\'kkk\',\'age\':18}
  • name为子进程的名称

创建进程的两种方式:

#开启进程方式一
from multiprocessing import Process
import time

def test(name):
    print(\'%s is running\' %name)
    time.sleep(3)
    print(\'%s is done\' %name)

if __name__==\'__main__\':
    p=Process(target=test,args=(\'hello\',))
    p.start()
    print(\'main\')


#开启子进程方式二
from multiprocessing import Process
import time

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

    def run(self):
        print(\'%s is running\' %self.name)
        time.sleep(3)
        print(\'%s is done\' %self.name)

if __name__==\'__main__\':
    p=MyProcess(\'hi\')
    p.start()
    print(\'main\')
View Code

5.进程中一些常见问题

  • 进程中不同进程间数据是互不联通通的
  • from multiprocessing import Process
    import os
    n=100
    
    def test():
        global n
        n=0
        print(\'%s进程中n=%s\' %(os.getpid(),n))
    
    
    if __name__ == \'__main__\':
        p=Process(target=test)
        p.start()
        print(\'主进程中n=%s\' %n)
    
    #主进程中n=100,没有被修改
    #子进程n=0,
    View Code

     

  • 守护进程:守护父进程,父进程结束后,守护进程无论是否结束都退出。守护进程要在start开启前,设置为守护进程后不能再开启子进程。
  • from multiprocessing import Process
    import time
    
    
    def test(name):
        print(\'%s为守护子进程staring\'%name)
        time.sleep(3)
        print(\'%s为守护子进程ending\' % name)
    
    if __name__==\'__main__\':
        p1=Process(target=test,args=(\'Hi\',))
        p1.daemon=True
        p1.start()
        print(\'main\')
    
    #仅输出main
    View Code

     

  • jion方法,会阻塞子进程,直到子进程完事后父进程才开启
  • from multiprocessing import Process
    import time
    
    def test(name):
        print(\'%s is running\' %name)
        time.sleep(3)
        print(\'%s is done\' %name)
    
    if __name__==\'__main__\':
        p=Process(target=test,args=(\'hello\',))
        p.start()
        p.join()
        print(\'main\')
    
    #hello is running
    #hello is done
    #main
    View Code

     

6.进程互斥锁

一个主进程中各子进程间数据是不能互相通信的,但可以通过访问外部同一个文件来实现共享,但共享带来的是竞争,竞争带来的结果就是混乱。解决方式就是加锁。

from multiprocessing import Process, Lock
import time
import json
import random
import os


def search():
    time.sleep(random.randint(1,3))
    dic=json.load(open(\'1.txt\',\'r\',encoding=\'utf-8\'))
    print(\'%s 查询到余票%s\' %(os.getpid(),dic[\'count\']))

def get():
    time.sleep(random.randint(1,3))
    dic=json.load(open(\'1.txt\',\'r\',encoding=\'utf-8\'))
    if(dic[\'count\']>0):
        dic[\'count\']-=1
        time.sleep(random.randint(1,3))
        json.dump(dic, open(\'1.txt\', \'w\', encoding=\'utf-8\'))
        print(\'%s购票成功\'%os.getpid())

def task(mutex):
    search()
    mutex.acquire()
    get()
    mutex.release()


if __name__==\'__main__\':
    mutex=Lock() #设置锁
    for i in range(10):
        p=Process(target=task,args=(mutex,))
        p.start()
View Code

存在问题:加锁可以保证多个进程修改同一块数据时,只允许自有一个任务是可以修改,即串行修改,运行速度慢却保证了数据安全。该方式效率低(数据基于共享文件,而文件在磁盘上)、需要自己加锁处理。

7.队列:实现进程间互相通信的方式

队列是一种先进先出存储方式,

from multiprocessing import Queue

q=Queue(3)#定义一个队列大小,可以不指定
q.put(\'first\')   #插入数据,当队列满时会阻塞
q.put({\'count\':1})
q.put(1)
q.put(\'de\',block=True,timeout=3)
print(q.get()) #拿数据
View Code

队列实现进程通信:

from multiprocessing import Process,Queue

def f1(q):
    q.put(\'hi\')
def f2(q):
    print(q.get())

if __name__==\'__main__\':
    q=Queue()
    p=Process(target=f1,args=(q,))
    p1=Process(target=f2,args=(q,))
    p.start()
    p1.start()
View Code

8.生产者消费者模型

在并发编程中使用生产者消费者模式可以解决大多数并发问题。通过一个容器来解决生产者和消费者的强耦合问题。生产者和消费者间不直接通信,而阻塞队列来进行通信,所以生产者生产玩数据后不用等待消费者的处理,直接扔给阻塞队列,消费者不用找生产者要数据,而直接从阻塞队列中取。阻塞队列就相当于一个缓冲区,平衡了消费者和生产者的能力。

import time
import random
from multiprocessing import Process,Queue,JoinableQueue

def producer(name,q):
    for i in range(3):
        r=\'包子%s\' %i
        print(\'%s制作包子%s\' %(name,i))
        time.sleep(random.randint(1, 3))
        q.put(r)

def consumer(name,q):
    while True:
        res=q.get()
        if res==\'NULL\':break
        print(\'%s吃包子%s\' %(name,res))
        time.sleep(random.randint(1, 3))
        q.task_done()


if __name__=="__main__":
    #q=Queue()
    q=JoinableQueue()
    p=Process(target=producer,args=(\'gg\',q,))
    p1 = Process(target=producer, args=(\'gg1\', q,))
    c=Process(target=consumer,args=(\'cc\',q))
    c1 = Process(target=consumer, args=(\'cc1\', q))
    c2= Process(target=consumer, args=(\'cc2\', q))
    p.start()
    p1.start()

    c.daemon=True
    c1.daemon=True
    c2.daemon=True
    c.start()
    c1.start()
    c2.start()

    p.join()
    p1.join()
    q.join()

    print(\'main\')
View Code

 

 

 

 

 

以上是关于python进程的主要内容,如果未能解决你的问题,请参考以下文章

[Python3] 043 多线程 简介

java 简单的代码片段,展示如何将javaagent附加到运行JVM进程

代码片段:Shell脚本实现重复执行和多进程

python中的多线程和多进程编程

使用 asyncio 将 bash 作为 Python 的子进程运行,但 bash 提示被延迟

LINUX PID 1和SYSTEMD PID 0 是内核的一部分,主要用于内进换页,内核初始化的最后一步就是启动 init 进程。这个进程是系统的第一个进程,PID 为 1,又叫超级进程(代码片段