欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

进程一

程序员文章站 2022-06-24 14:47:43
一、什么是进程 进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。在早期面向进程设计的计算机结构中,进程是程序的基本执行实体;在当代面向线程设计的计算机结构中,进程是线程的容器。程序是指令、数据及其组织形式的描述,进程是程 ......

一、什么是进程

  进程(process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。在早期面向进程设计的计算机结构中,进程是程序的基本执行实体;在当代面向线程设计的计算机结构中,进程是线程的容器。程序是指令、数据及其组织形式的描述,进程是程序的实体。我们自己在python文件中写了一些代码,这叫做程序,运行这个python文件的时候,这叫做进程。

  狭义定义:进程是正在运行的程序的实例(an instance of a computer program that is being executed)。

  广义定义:进程是一个具有一定独立功能的程序关于某个数据集合的一次运行活动。它是操作系统动态执行的基本单元,在传统的操作系统中,进程既是基本的分配单元,也是基本的执行单元
  1,进程的概念
  第一,进程是一个实体。每一个进程都有它自己的地址空间,一般情况下,包括文本区域(text region)(python的文件)、数据区域(data region)(python文件中定义的一些变量数据)和堆栈(stack region)。文本区域存储处理器执行的代码;数据区域存储变量和进程执行期间使用的动态分配的内存;堆栈区域存储着活动过程调用的指令和本地变量。
  第二,进程是一个“执行中的程序”。程序是一个没有生命的实体,只有处理器赋予程序生命时(操作系统执行之),它才能成为一个活动的实体,我们称其为进程。进程是操作系统中最基本、重要的概念。是多道程序系统出现后,为了刻画系统内部出现的动态情况,描述系统内部各道程序的活动规律引进的一个概念,所有多道程序设计操作系统都建立在进程的基础上。
  2,进程的特征
    动态性:进程的实质是程序在多道程序系统中的一次执行过程,进程是动态产生,动态消亡的。
    并发性:任何进程都可以同其他进程一起并发执行
    独立性:进程是一个能独立运行的基本单位,同时也是系统分配资源和调度的独立单位;
    异步性:由于进程间的相互制约,使进程具有执行的间断性,即进程按各自独立的、不可预知的速度向前推进
    结构特征:进程由程序、数据和进程控制块三部分组成。
    多个不同的进程可以包含相同的程序:一个程序在不同的数据集里就构成不同的进程,能得到不同的结果;但是执行过程中,程序不能发生改变。
  注意:同一个程序执行两次,就会在操作系统中出现两个进程,所以我们可以同时运行一个软件,分别做不同的事情也不会混乱

二、并发与并行,同步与异步

  并发:伪并行,就是几个进程共用一个cpu,几个进程之间是时间轮换的,而这个轮换时间很短,肉眼是看不到的,所以我们肉眼看到的是几个进程同时在进行,其他中间有停止的,只是停止时间短,这就叫并发

  并行:指一个进程就用一个cpu,每个进程是没有停止的,就是一起运行的

  同步:一个任务执行完后,另一个任务才能开始执行,就是有一个任务需要等待,这样两个任务之间的关系是同根生的,非常紧密的

  异步:两个任务之间没有关联,你执行你的,我执行我的,互相不用等待

三、进程的创建方法

  1,方法一

from multiprocessing import process            #引入进程模块,
import os,time
def fun1():
    time.sleep(2)
    print('jjjj')
def fun2():
    time.sleep(3)
    print('ddada')
    print(os.getpid())                #获得子进程的进程id
    print(os.getppid())                #获得子进程的父进程,即主进程的id
if __name__=="__main__":            #记住,必须用  if  main 
    start_time=time.time()           #开始时间
    p=process(target=fun2)             #创建一个子进程
    p.start()                         #开始子进程
    fun1()
    print(os.getpid())               #获得主进程的进程id
    end_time=time.time()              #结束时间
    print(end_time-start_time)          #打印总共用时
整段程序走完用时2秒多一点,但是如果我们按照以前的写法,先执行fun1(),再执行fun2(),至少得花5秒

  2,方法二

from multiprocessing import process       #同样引入模块
import time
class mypro(process):                 #创建一个类,继承process
    def __init__(self,name):
        super().__init__()
        self.name=name
    def run(self):                 #这是必须的方法,然后要执行的程序写在方法里面就行
        time.sleep(3)
        print(self.name)
if __name__ == '__main__':        #记住,这里必须写 if main
    p1=mypro('huangchun')         #用自己定义的类创建一个子进程
    p1.start()                    #子进程开始
    p1.join()                    #这是join方法,这样写就是join后面的主进程程序必须等子进程执行完后在执行,两种方法都可以用
    print('我是主进程,哈哈哈哈哈哈。。。。。')

四、守护进程

  把一个子进程设为守护进程之后,每当主进程执行完毕后,不管你子进程有没有执行完毕,都要跟着结束

from multiprocessing import process
import time
def fun():
    time.sleep(5)
    print('我是子进程')
if __name__ == '__main__':
    p=process(target=fun)
    p.daemon = true            #这就是把子进程设为了守护进程,但是切记,这句代码必须写在start()前面
    p.start()
    print('我主进程,哈哈哈哈哈哈')
没有设置守护进程之前,代码要执行5秒才结束,等到子进程执行完才结束,但是设置为守护进程之后,代码瞬间执行完毕,只打印了主进程的内容,而子进程的print直接死了

五、同步锁(互斥锁)

  对一段程序设置同步锁之后,不管你对这段程序开了几个进程,但只有一个进程能执行代码,而其他的进程需要等待前面的进程结束之后才能执行这段代码,就相当于把开的几个进程搞成同步了,互相约束着

这是模拟抢火车票的情景,在还没付钱确认之前,大家都看见了有一张票,但是只有一个人能抢到票
from multiprocessing import process,lock #引入lockmok import time def fun1(i): #这是查看余票的方法 with open('piao.txt',mode='r',encoding='utf-8')as f1: num=f1.read() print('%s客户看到票还有%s张'%(i,num)) def fun(i,lo): #这是买票的方法 time.sleep(1) lo.acquire() #这是同步锁的开始, with open('piao.txt',mode='r',encoding='utf-8')as f1: num=f1.read() if num=='1': print('%s买到票了'%i) num=int(num)-1 elif num=='0': print('%s没票了'%i) with open('piao.txt', mode='w', encoding='utf-8')as f1: f1.write(str(num)) lo.release() 这是同步锁的结束 if __name__ == '__main__': lo=lock() #这是创建一把锁 for i in range(10): #这是循环创建10个客户 fun1(i) #这是客户查看余票 p=process(target=fun,args=(i,lo)) #创建子进程去抢票,然后把锁传给进程 p.start()
同步锁把抢票的程序锁起来了,所以,虽然有10个客户都在抢票,但实际上只有一人能进入抢票程序,其他的人要等待第一个进抢票程序的人执行完后才能又进一个人,反正每次就只允许一个人在使用抢票程序,其他的人继续排队

六、信号量

  信号量就是对一段程序设定允许最多几个人使用,相当于一个饭店,只有四个位置,最多允许四个人吃饭,后面人要等待前面的人吃完才能进入饭店吃,前面走一个,就可以进一个

from multiprocessing import process,semaphore      #引入semaphore模块
import time
def fun(s,i):                    
    s.acquire()
    print('%s客户在吃'%i)
    time.sleep(1)
    print('%s客户吃完了'%i)
    time.sleep(1)
    s.release()
if __name__ == '__main__':
    s=semaphore(4)          #创建信号量对象
    for i in range(10):          #循环创建10个人去饭店吃饭
        p=process(target=fun,args=(s,i)) #创建饭店子进程,然后把信号量传给子进程
        p.start()

七、事件

  在创建事件之后默认值为false,我们可以把创建的事件对象传给子进程,然后在子进程中事件对象.set(),使得指变为ture。然后我们在主进程中加上事件对象.wait(),在此处,只有当值为ture时不会阻塞,值为false就会阻塞,

从而我们可以用此方法来影响主进程的执行。

from multiprocessing import process,event   #引入event模块
import time
def func(e):
    print('子进程开始执行')
    time.sleep(3)
    print('子进程结束')
    e.set()                      #设置事件值为ture,我们还可以通过e.clear()把值改为false
if __name__ == '__main__':
    e=event()                   #创建事件对象e,此时默认值为false
    p=process(target=func,args=(e,))       #创建子进程,把e传给子进程
    p.start()
    print('等待子进程结束后拿到值')
    e.wait()                    #当值为false会阻塞,当值为ture是,不会阻塞,因为我们在子进程中最好把值改为ture,所以wait()以后的程序要等到子进程执行完才能执行
    print('拿到值,执行主进程')
    time.sleep(1)
    print('主进程执行完毕')

八、队列,消费者生产者模型,joinablequeue

  1,队列

  队列就相当于一个容器,里面可以放数据,特点是先放进去先拿出来,即先进先出,

from multiprocessing import queue       #引入queue模块
q=queue(2)                           #创建一个队列对象,并给他设置容器大小,即能放几个数据
q.put(1)                             #put()方法是往容器里放数据
q.put(2)
q.put(3)                             #这是往容器里放第三个数据,由于只能放两个,所以此处会阻塞,不会报错,相当于死循环
q.put_nowait(4)                      #put_nowait()这也是从容器里放数据的方法,但如果容器满了,不会阻塞,会直接报错
q.get()                              #get()方法是从容器里拿数据
q.get()
q.get()                              #这是从容器里拿第三个数据,但是容器的两个数据拿完了,没有数据了,此时也会阻塞,不会报错,死循环
q.get(false)                         #这也是从容器里拿数据的方法,当没数据时不会阻塞,直接报错
q.get_nowait()                       #这也是从容器里拿数据的方法,当没数据时不会阻塞,直接报错
q.full()                             #这是查看容器是否满了,如果满了,返回ture,否则返回false
q.empty()                             #这是查看容器是否为空,如果为空,返回ture,否则返回false

  2,消费者生产者模型

  就是消费者和生产者之间不是直接联系的,而是通过中间的一个队列来进行联系的,生产者把生产的东西放进进队列里,消费者从队列里拿东西,其实消费者和生产者之间没有实质的联系

from multiprocessing import process,queue
import time
def sheng(q):              #生产者
    for i in range(10):
        time.sleep(1)
        q.put(i)
        print('包子%i生产完毕'%i)
    q.put('over')
def xiao(q):             #消费者
    while 1:
        time.sleep(1.5)
        ss=q.get()
        if ss=='over':
            break
        print('包子%s被吃了'%ss)
if __name__ == '__main__':
    q=queue(10)           #创建队列对象q
    p=process(target=sheng,args=(q,))        #创建生产者子进程,把q传给他
    p1=process(target=xiao,args=(q,))        #创建消费者子进程,也把q传给他
    p.start()
    p1.start()
有个问题就是,生产者要把生产结束的消息放进队列里,让消费者过去结束消息,消费者才知道队列里没有数据了,这样消费者才能停止,如果生产者不放结束消息,当生产者结束时,即不往队列放数据,而消费者不知道生产者已经结束,
还一直往队列拿数据,当队列没数据时,消费者一边就会阻塞。解决阻塞,有几个消费者,生产者就应该放几个结束消息,让每个消费者都知道,这样每个消费者才能结束。但是生产者又不知道有几个消费者,所以不知奥应该放几个结束数据,
这样就无法解决对消费者现象。此时,我们就就可以引入joinablequeue

  3,joinablequeue

  他其实就是一种队列,但她又比队列要多两种方法,task_done()和join()方法,正是有这两种方法就可以解决上面的问题

from multiprocessing import process,joinablequeue      #引入joinablequeue模块
import time
def sheng(q):        #生产者
    for i in range(10):
        time.sleep(1)
        q.put(i)
        print('包子%i生产完毕'%i)
    q.join()                   #当q收到的task_done数量等于放进q的数据数量时,生产者就结束了
def xiao(q,i):                    #消费者
    while 1:
        time.sleep(1.5)
        ss=q.get()
        if ss=='over':
            break
        print('%s客户吃包子%s'%(i,ss))
        q.task_done()                  #消费者每从q里取一个值,就向q返回一个task_done消息
if __name__ == '__main__':
    q=joinablequeue()                   #创建joinablequeue对象q
    p=process(target=sheng,args=(q,))    #创建生产者子进程,把q传给他
    p.start()
    for i in range(3):                      #循环创建消费者子进程,把q传给他
        p1=process(target=xiao,args=(q,i))
        p1.daemon=true                   #把创建的每个消费者子进程设为守护进程
        p1.start()
    p.join()                              #主进程要等到生产者子进程结束后才结束
整个个过程就是:生产者生产了10个包子,3个消费者吃包子,没吃一个包子往q里发一个task_done,当q拥有10个task_done时,意味着10个包子吃完了,此时,生产者就结束了,接着主进程也也结束了,然后守护进程跟着结束了,即所有的消费者子进程结束,解决上面所遇到的问题