进程1

1.进程理论
   
 程序:一堆代码
    进程:正在运行的程序
    进程是一个实体。每一个进程都有它自己独立的内存空间,是系统进行资源分配和调度的基本单位
  
  同步和异步
*****

  针对任务的提交方式
    同步:提交任务之后原地等待任务的返回结果,期间不做任何事!
    异步:提交任务之后,不等待任务的返回结果,直接执行下一步操作
  
阻塞与非阻塞 *****

  针对程序运行的状态
    阻塞:遇到io操作(文件读写....)    >>> 阻塞态(Blocked
    非阻塞:就绪或者运行态            >>> 就绪态(Ready),运行态(Running

 

先来先服务调度算法 FCFS
    #适合于CPU繁忙型作业,而不利于I/O繁忙型的作业(进程)。
短进程优先调度算法 SJ/PF
    #既可用于作业调度,也可用于进程调度。但其对长作业不利;不能保证紧迫性作业(进程)被及时处理
时间片轮转法 RR,Round Robin
    #让每个进程在就绪队列中的等待时间与享受服务的时间成比例
    #对这些进程区别对待,给予不同的优先级和时间片,可以进一步改善系统服务质量和效率
多级反馈队列调度算法
    #(1) 应设置多个就绪队列,并为各个队列赋予不同的优先级。第一个队列的优先级最高,第二个队列次之,其余各队列的优先权逐个降低。该算法赋予各个队列中进程执行时间片的大小也各不相同,在优先权愈高的队列中,为每个进程所规定的执行时间片就愈小。例如,第二个队列的时间片要比第一个队列的时间片长一倍,……,第i+1个队列的时间片要比第i个队列的时间片长一倍。
    #(2) 当一个新进程进入内存后,首先将它放入第一队列的末尾,按FCFS原则排队等待调度。当轮到该进程执行时,如它能在该时间片内完成,便可准备撤离系统;如果它在一个时间片结束时尚未完成,调度程序便将该进程转入第二队列的末尾,再同样地按FCFS原则等待调度执行;如果它在第二队列中运行一个时间片后仍未完成,再依次将它放入第三队列,……,如此下去,当一个长作业(进程)从第一队列依次降到第n队列后,在第n 队列便采取按时间片轮转的方式运行。

    #(3) 仅当第一队列空闲时,调度程序才调度第二队列中的进程运行;仅当第1~(i-1)队列均空时,才会调度第i队列中的进程运行。如果处理机正在第i队列中为某进程服务时,又有新进程进入优先权较高的队列(第1~(i-1)中的任何一个队列),则此时新进程将抢占正在运行进程的处理机,即由调度程序把正在运行的进程放回到第i队列的末尾,把处理机分配给新到的高优先权进程。
操作系统的调度算法

2.开启进程的两种方式(***)

  本质:在内存中申请一块独立的内存空间

  windows下创建进程内部实现:

    以模块导入的方式将代码拷贝到新申请的内存空间中

创建进程的开销比较大:
  申请内存空间
  拷贝代码

  创建进程的方式 1:

    自己定义一个函数,调用Process(target='自己写的函数',args=(v1,))

from multiprocessing import Process
import time

def task(name): print('%s is running'%name) time.sleep(3) print('%s is over'%name) # 注意,在windows系统中,创建进程会将代码以模块的方式从头到尾加载一遍 # 一定要写在if __name__ == '__main__':代码块里面 # 强调:函数名一旦加括号,执行优先级最高,立刻执行 if __name__ == '__main__': p1 = Process(target=task,args=('Tom',)) # 这一句话只是实例化了一个Process对象 p1.start() # 告诉操作系统创建一个进程 print('主程序') >>>:   主程序   Tom is running   Tom is over

  创建进程的方式 2

    写一个类继承Process,在里面固定写一个run方法

from multiprocessing import Process
import time


class MyProcess(Process):

    def __init__(self, name):
        super().__init__()
        self.name = name

    # 必须写run方法
    def run(self):
        print('%s is running' % self.name)
        time.sleep(1)
        print('%s is end' % self.name)


if __name__ == '__main__':
    obj = MyProcess('Tom')
    obj.start()
    print('主程序')


>>>:
  主程序
  Tom is running
  Tom is end

 3.进程对象的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__':
    start_time = time.time()
    p_list = []
    for i in range(3):
        p = Process(target=task, args=('子进程%s' % i, i))
        p.start()
        p_list.append(p)
    for i in p_list:
        i.join()
    print('主进程', time.time() - start_time)

# join的作用仅仅只是让主进程等待子进程的结束,不会影响子进程的运行

>>>:
    子进程0 is running
    子进程0 is over
    子进程1 is running
    子进程2 is running
    子进程1 is over
    子进程2 is over
    主进程 2.10233998298645



# if 初始写法  ------------------------------
if __name__ == '__main__':
    start_time = time.time()
    p1 = Process(target=task,args=('egon',1))
    p2 = Process(target=task,args=('jason',2))
    p3 = Process(target=task,args=('kevin',3))
    start_time = time.time()
    p1.start()  # 千万要知道,这句话只是告诉操作系统需要进程
    p2.start()
    p3.start()
    # p1.join()  # 主进程等待子进程结束 才继续运行
    p3.join()
    p1.join()
    p2.join()
    print('主进程', time.time() - start_time)

 4.进程之间内存隔离(***)

# 记住 进程与进程之间数据是隔离的!!!
from multiprocessing import Process

x = 100


def task():
    global x
    x = 1
    print('task - x :', x)


if __name__ == '__main__':
    p = Process(target=task)
    p.start()
    p.join()
    print('主 - x:', x)


>>>:
    task - x : 1- x: 100

 5.进程对象其他相关方法

查看进程id号
  current_process().pid    >>> current_process()返回的是Process()
  os.getpid()  os.getppid()
  
  terminate()  主动发起杀死进程的操作
  time.sleep(0.1)
  is_alive()  判断进程是否存活

from multiprocessing import Process,current_process
import time
import os


def task():
    print('%s is running'%os.getpid())
    time.sleep(3)
    print('%s is over'%os.getppid())


if __name__ == '__main__':
    p1 = Process(target=task)  # 函数名(),执行优先级最高
    p1.start()
    p1.terminate()  # 杀死子进程
    time.sleep(0.1)
    print(p1.is_alive())  # 判断子进程是否存活
    print('')



>>>:
    False
    主

 6.僵尸进程与孤儿进程  

  子进程结束之后不会立即释放pid等资源信息

  任何进程都会步入僵尸进程,当主进程不停的创建子进程的时候,会有害

两种情况下会回收子进程的pid等信息

  1.父进程正常结束   

  2.join方法       

孤儿进程:父进程意外意外死亡     

  linux下:    

    init孤儿福利院;用来回收孤儿进程所占用的资源  

    ps aux |grep 'Z'  (查看孤儿进程)

 7.守护进程

  主进程一旦运行完毕,子进程立即结束运行(一起死!)

from multiprocessing import Process
import time


def task(name):
    print('%s 正活着' % name)
    time.sleep(3)
    print('%s 正常死亡' % name)


if __name__ == '__main__':
    p = Process(target=task, args=('总管',))  # 容器型:只有一个元素,加逗号","
    p.daemon = True  # 必须在p.start开启进程命令之前声明
    p.start()
    print('皇帝正在死亡')


>>>:
    皇帝正在死亡

 8.互斥锁(***) 锁千万不要随意去用 

  实质:加锁会将并发变成串行    

  作用:解决多个进程操作同一份数据,造成数据不安全的情况

  结果:牺牲了效率但是保证了数据的安全     

  位置:锁一定要在主进程中创建,给子进程去用 

  作用点:锁通常用在对数据操作的部分,并不是对进程全程加锁

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


def search(i):
    with open('info', 'r', encoding='utf-8') as f:
        data = json.load(f)
    print('用户查询余票数:%s' % data.get('ticket'))


def buy(i):
    # 买票之前还得先查有没有票!
    with open('info', 'r', encoding='utf-8') as f:
        data = json.load(f)
    time.sleep(random.randint(1, 3))  # 模拟网络延迟
    if data.get('ticket') > 0:
        data['ticket'] -= 1  # 买票
        with open('info', 'w', encoding='utf-8') as f:
            json.dump(data, f)
        print('用户%s抢票成功' % i)
    else:
        print("用户%s查询余票为0" % i)


def run(i, mutex):
    search(i)
    mutex.acquire()  # 抢锁   一把锁不能同时被多个人使用,没有抢到的人,就一直等待锁释放
    buy(i)
    mutex.release()  # 释放锁


if __name__ == '__main__':
    mutex = Lock()
    for i in range(10):
        p = Process(target=run, args=(i, mutex))
        p.start()


# info 内容:
{"ticket": 1}


>>>:
    用户查询余票数:1
    用户查询余票数:1
    用户查询余票数:1
    用户0抢票成功
    用户1查询余票为0
    用户2查询余票为0

 

posted @ 2019-05-06 19:34  zhoyong  阅读(166)  评论(0编辑  收藏  举报