Python 计算机发展史 多道技术 进程 守护进程 孤儿和僵尸进程 互斥锁

一 计算机发展史

操作系统本质上是一个软件

主要功能:

  1、控制硬件,隐藏丑陋复杂的硬件细节

  2、将无序的硬件竞争变得有序

 

第一代计算机(1940~1955):真空管和穿孔卡片

第二代计算机(1955~1965):晶体管和批处理系统

第三代计算机(1965~1980):集成电路芯片和多道程序设计

         第三代计算机的操作系统仍然是批处理

第四代计算机(1980~至今):个人计算机

二 多道技术(第三代计算机出现)

1.产生背景:针对单核,实现并发
    ps:
    现在的主机一般是多核,那么每个核都会利用多道技术
    有4个cpu,运行于cpu1的某个程序遇到io阻塞,会等到io结束再重新调度,会被调度到4个
    cpu中的任意一个,具体由操作系统调度算法决定。
    
    2.空间上的复用:如内存中同时有多道程序
    3.时间上的复用:复用一个cpu的时间片
       强调:遇到io切,占用cpu时间过长也切,核心在于切之前将进程的状态保存下来,这样
            才能保证下次切换回来时,能基于上次切走的位置继续运行
View Code

空间复用:多个程序共用一套计算机硬件,每个程序间的内存都是相互隔离的(物理隔离)

时间复用(切换+保存):当一个程序执行IO操作时,切换到另一个程序来执行,光切换还不行 必须在切换前保存当前的状态 以便与恢复执行。

注意:并不是多道就一定提高了效率
如果多个任务都是纯计算 那么切换反而降低了效率
遇到IO操作才应该切换 这才能提高效率

三 同步 异步 阻塞 非阻塞 并发 并行

#同步和异步指的是任务的提交方式

1.同步:任务提交之后 原地等待的任务的执行并拿到返回结果才走 期间不做任何事(程序层面的表现就是卡住了)

2.异步:任务提交之后 不再原地等待 而是继续执行下一行代码(结果是要的 但是是用过其他方式获取)

 

#阻塞和非阻塞指的程序运行的状态

1.阻塞:当程序执行过程中遇到了IO操作,在执行IO操作时,程序无法继续执行其他代码,称为阻塞!

2.非阻塞:程序在正常运行没有遇到IO操作,或者通过某种方式使程序即时遇到了也不会停在原地,还可以执行其他操作,以提高CPU的占用率

 

强调:同步异步 阻塞非阻塞是两对概念 不能混为一谈

 

 

并发:指的是多个进程快速切换执行,间隔时间很短看起来像是同时执行的。

并行:真正意义上的多个进程同时执行的(多核cpu才能完成)

 

进程的三种状态

 

 

四 进程

1.什么是进程:正在运行的程序,程序是程序员编程的一堆代码(字符串),当这对代码被系统加载的内存中执行时,就有了进程(也是操作系统在调度和进行资源分配的基本单位) 

 当一个进程a开启了另一个进程b时,a称为b的父进程,b称为a的子进程

2.实现进程的两种方式

1.实例化Process类
from multiprocessing import Process
import time

def task(name):
    print('%s is running' %name)
    time.sleep(3)
    print('%s is done' %name)
if __name__ == '__main__':
    # 在windows系统之上,开启子进程的操作一定要放到这下面
    # Process(target=task,kwargs={'name':'egon'})
    p=Process(target=task,args=('jack',)) # 实例化产生进程对象
    p.start() # 向操作系统发送请求,操作系统会申请内存空间,然后把父进程的数据拷贝给子进程,作为子进程的初始状态
    print('======主')

2.继承Process类 并覆盖init 和 run方法
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('jack')
    p.start()

需要注意的是 

1.在windows下 开启子进程必须放到`__main__`下面,因为windows在开启子进程时会重新加载所有的代码造成递归创建进程

2.第二种方式中,必须将要执行的代码放到run方法中,子进程只会执行run方法其他的一概不管
    print('')
View Code

3.进程中的join()函数  阻塞

Process的对象具备一个join函数

用于提高子进程优先级 ,使得父进程等待子进程结束

from multiprocessing import Process

def task():
    print("子进程 Game Over")

if __name__ == '__main__':
    p = Process(target=task)
    p.start()
    p.join()    # 等待子进程执行完毕,将子进程的优先级提高
    print("主进程 Game Over")    # 子进程 Game Over
                                 # 主进程 Game Over
View Code

4.进程中的内存都是相互隔离的

from multiprocessing import Process
x = 10
def task():
    global x
    x = 100
    print("子进程",x)   # 子进程 100

if __name__ == '__main__':
    p = Process(target=task)
    p.start()
    print("父进程",x)    # 父进程 10


创建进程就是在内存中重新开辟一块内存空间
将允许产生的代码丢进去
一个进程对应在内存就是一块独立的内存空间

进程与进程之间数据是隔离的 无法直接交互
但是可以通过某些技术实现间接交互
View Code

5.进程对象及其他方法

from multiprocessing import Process
def task(n):
    print('%s is runing' %n)
    time.sleep(n)

if __name__ == '__main__':
    start_time=time.time()
    p1=Process(target=task,args=(1,),name='任务1')
    p1.start() # 启动进程
    print(p1.pid) # 获取进程pid
    print(p1.name) # 获取进程名字
    p1.terminate() # 终止进程
    p1.join() # 提高优先级
    print(p1.is_alive()) # 获取进程的存活状态
    print('')
View Code

6.pid和ppid

#1.什么是pid: 一个操作系统中通常都会运行多个应用程序,也就是多个进程,那么如何来区分进程呢?系统会给每一个进程分配一个进程编号即PID,如同人需要一个身份证号来区分。

#2.

# 在python中可以使用os模块来获取ppid
import os
print("self",os.getpid()) # 当前进程自己的pid
print("parent",os.getppid()) # 当前进程的父进程的pid
View Code

四 进程中的孤儿进程和僵尸进程

1.什么是孤儿进程:

孤儿进程指的是开启子进程后,父进程先于子进程终止了,那这个子进程就称之为孤儿进程

例如:qq聊天中别人发给你一个链接,点击后打开了浏览器,那qq就是浏览器的父进程,然后退出qq,此时浏览器就成了孤儿进程

孤儿进程是无害的,有其存在的必要性,在父进程结束后,其子进程会被操作系统接管。

2.什么是僵尸进程:僵尸进程指的是,当子进程比父进程先结束,而父进程又没有回收子进程,释放子进程占用的资源,此时子进程将成为一个僵尸进程。如果父进程先退出 ,子进程被操作系统接管,子进程退出后操作系统会回收其占用的相关资源!

五 进程中的守护进程

1.什么是守护进程:一个进程可以守护另一个进程。开启守护进程是为了并发执行某个任务,但这个任务如果伴随着主进程的结束而没有存在的意义,就可以将子进程设为守护进程。比如:qq接收到一个视频文件,于是开启了一个子进程来下载,如果中途退出了,下载任务就没必要继续下去。如果b是a的守护进程,a是被守护的进程,如果a挂了,则b也随之结束。

from multiprocessing import Process
import time


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


if __name__ == '__main__':
    p = Process(target=test,args=('egon',))
    p.daemon = True  # 将该进程设置为守护进程   这一句话必须放在start语句之前 否则报错
    p.start()
    time.sleep(0.1)
    print('皇帝jason寿正终寝')
View Code

六 进程中的互斥锁

1.什么是互斥锁:

互相排斥的锁,我在这站着你就别过来,(如果这个资源已经被锁了,其他进程就无法使用了)

需要强调的是: 锁 并不是真的把资源锁起来了,只是在代码层面限制你的代码不能执行

为什么需要互斥锁:

并发将带来资源的竞争问题 当多个进程同时要操作同一个资源时,将会导致数据错乱的问题

解决方案1:

加join, ​ 弊端 1.把原本并发的任务变成了穿行,避免了数据错乱问题,但是效率降低了,这样就没必要开子进程了 ​ 2.原本多个进程之间是公平竞争,join执行的顺序就定死了,这是不合理的

解决方案2:

就是给公共资源加锁,互斥锁 ​ 互斥锁 互相排斥的锁,我在这站着你就别过来,(如果这个资源已经被锁了,其他进程就无法使用了)

锁 并不是真的把资源锁起来了,只是在代码层面限制你的代码不能执行

锁和join的区别:

1.join是固定了执行顺序,会造成父进程等待子进程 锁依然是公平竞争谁先抢到谁先执行,父进程可以做其他事情

2.最主要的区别: join是把进程的任务全部串行 锁可以锁任意代码 一行也可以 可以自己调整粒度

#  当多个进程操作同一份数据的时候 会造成数据的错乱
#         这个时候必须加锁处理
#             将并发变成串行
#                 虽然降低了效率但是提高了数据的安全
#             注意:
#                 1.锁不要轻易使用 容易造成死锁现象
#                 2.只在处理数据的部分加锁 不要在全局加锁
#
#         锁必须在主进程中产生 交给子进程去使用

注意1:  不要对同一把执行多出acquire 会锁死导致程序无法执行  一次acquire必须对应一次release

```python
 l = Lock()
 l.acquire()
 print("抢到了!")
 l.release()
 l.acquire()
 print("强哥毛线!")
```

注意2:想要保住数据安全,必须保住所有进程使用同一把锁



from multiprocessing import Process,Lock
import time
import json

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

# 买票
def buy(i):
    with open('data','r',encoding='utf-8') as f:
        data = f.read()
    t_d = json.loads(data)
    time.sleep(1)
    if t_d.get('ticket') > 0:
        # 票数减一
        t_d['ticket'] -= 1
        # 更新票数
        with open('data','w',encoding='utf-8') as f:
            json.dump(t_d,f)
        print('用户%s抢票成功'%i)
    else:
        print('没票了')


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()
View Code

 

posted @ 2019-08-09 20:01  心慌得初夏  阅读(266)  评论(0编辑  收藏  举报
levels of contents