并发编程值进程

概念:

进程是一个正在执行的程序,或者说一个任务,是CPU的基本执行单元。

程序和进程:程序是一个静态的概念,进程是一个动态的概念;程序可以脱离机器长期保存,进程是执行后的程序;程序可以多次执行并产生多个不同的进程 当然可以用代码控制是否允许多进程。

并行与并发:无论是并行还是并发,在使用者看来,都是‘同时’运行的,不管是线程还是进程,都只是一个任务而已,真正干货的是CPU,cou来做这些任务,而一个CPU在同一时刻只能处理执行一个任务。

并发:也称作伪并行,即看起来是同事运行。单个CPU+多道技术就可以实现并发

并行:同时运行,只有具备多个CPU才能实现,但是针对每个cpu依旧是依靠多道技术在运行,调配cpu资源,例如:你的计算机有四个核,但是现在有6个任务,这样在同一时刻就有四个任务在执行了,当其中一个任务遇到I/O阻塞或者占用cpu时间过长时,便会被切走执行其他任务。

同步:就是在同一个功能调用时,在没有得到结果之前,该调用就不会返回。按照这个定义绝大多数函数都是同步调用。但是一般而言,我们在说同步、异步的时候,特指那些需要其他部件协作或者需要一定时间完成的任务。

例子:你打电话问书店老板有没有《分布式系统》这本书,如果是同步通信机制,书店老板会说,你稍等,”我查一下",然后开始查啊查,等查好了(可能是5秒,也可能是一天)告诉你结果(返回结果)。同步

异步:当一个异步功能调用发出后,调用者不能立刻得到结果。当该异步功能完成后,通过状态、通知或回调来通知调用者。如果异步功能用状态来通知,那那么调用者每隔一定时间检查一次,效率很低。如果使用通知的方式,效率很高,因为异步功能几乎不许需要做额外的操作。回调函数,其实和通知差不多。

例子:而异步通信机制,书店老板直接告诉你我查一下啊,查好了打电话给你,然后直接挂电话了(不返回结果)。然后查好了,他会主动打电话给你。在这里老板通过“回电”这种方式来回调。异步

阻塞调用:是指调用结果返回之前呢,当前线程会被挂起(如遇到IO操作)。函数只有在得到结果之后才会将最的线程激活。

非阻塞调用:是相对于阻塞调用来说:指不能再立刻得到结果之前也会立刻返回,同时函数不会则是当前线程

例子:你打电话问书店老板有没有《分布式系统》这本书,你如果是阻塞式调用,你会一直把自己“挂起”,直到得到这本书有没有的结果,如果是非阻塞式调用,你不管老板有没有告诉你,你自己先一边去玩了, 当然你也要偶尔过几分钟check一下老板有没有返回结果。

这里的阻塞与非阻塞与是否同步异步无关,也跟书店老板通过什么方式回答你结果无关。

大例子:

老张爱喝茶,废话不说,煮开水。
出场人物:老张,水壶两把(普通水壶,简称水壶;会响的水壶,简称响水壶)。
1 老张把水壶放到火上,立等水开。(同步阻塞)
老张觉得自己有点傻
2 老张把水壶放到火上,去客厅看电视,时不时去厨房看看水开没有。(同步非阻塞)
老张还是觉得自己有点傻,于是变高端了,买了把会响笛的那种水壶。水开之后,能大声发出嘀~~~~的噪音。
3 老张把响水壶放到火上,立等水开。(异步阻塞)
老张觉得这样傻等意义不大
4 老张把响水壶放到火上,去客厅看电视,水壶响之前不再去看它了,响了再去拿壶。(异步非阻塞)
老张觉得自己聪明了。

所谓同步异步,只是对于水壶而言。
普通水壶,同步;响水壶,异步。
虽然都能干活,但响水壶可以在自己完工之后,提示老张水开了。这是普通水壶所不能及的。
同步只能让调用者去轮询自己(情况2中),造成老张效率的低下。

所谓阻塞非阻塞,仅仅对于老张而言。
立等的老张,阻塞;看电视的老张,非阻塞。
情况1和情况3中老张就是阻塞的,媳妇喊他都不知道。虽然3中响水壶是异步的,可对于立等的老张没有太大的意义。所以一般异步是配合非阻塞使用的,这样才能发挥异步的效果。(例子转载至知乎)

小结:1. 同步与异步针对的是函数/任务的调用方式:同步就是当一个进程发起一个函数(任务)调用的时候,一直等到函数(任务)完成,而进程继续处于激活状态。而异步情况下是当一个进程发起一个函数(任务)调用的时候,不会等函数返回,而是继续往下执行当,函数返回的时候通过状态、通知、事件等方式通知进程任务完成。 #2. 阻塞与非阻塞针对的是进程或线程:阻塞是当请求不能满足的时候就将进程挂起,而非阻塞则不会阻塞当前进程

进程创建

无论哪一种,新进程的创建都是由一个已经存在的进程执行了一个用于创建进程的系统调用而创建的:

  1. 在UNIX中该系统调用是:fork,fork会创建一个与父进程一模一样的副本,二者有相同的存储映像、同样的环境字符串和同样的打开文件(在shell解释器进程中,执行一个命令就会创建一个子进程)

  2. 在windows中该系统调用是:CreateProcess,CreateProcess既处理进程的创建,也负责把正确的程序装入新进程。

关于创建子进程:

相同点:进程创建后,父进程与子进程都有各自不同的地址空间(多道技术要求物理层面实现进城之间的内存隔离),任何一个金恒在其地址空间中的修改都不会影响到另外一个进程。

不同:在UNIX,子进程的初始地址空间死父进程的的一个副本,提示子进程好人父进程是可以有只读的共享内存区的。但是在windows系统上,从一开始父进程与子进程的地址空间就是不同的。

windows创建一个进程:

#coding=utf-8
from multiprocessing import Process
import os

def task1(name,age):
    print("子进程1: %s:开始" %os.getpid())
    print("name:%s,age:%s" %(name,age))
    print("子进程1: %s:结束" %os.getpid())

def task2(name,age):
    print("子进程2: %s:开始" % os.getpid())
    print("name:%s,age:%s" % (name, age))
    print("子进程2: %s:结束" % os.getpid())

#windows下必须拥有这一行,不认会导致重复创建进程,然后内存溢出报错
if __name__ == '__main__':

    print("主进程%s:开始" %os.getpid())
    p2 =Process(target=task2,args=("duke",18))
    p2.start()

    p1 = Process(target=task1,args=("alex",19))
    p1.start()
    print("主进程%s:结束" % os.getpid())
#进程的执行顺序是随机的
"""
主进程2928:开始
主进程2928:结束
子进程2: 14736:开始
name:duke,age:18
子进程2: 14736:结束
子进程1: 14592:开始
name:alex,age:19
子进程1: 14592:结束"""

进程的终止:

1. 正常退出(自愿,如用户点击交互式页面的叉号,或程序执行完毕调用发起系统调用正常退出,在linux中用exit,在windows中用ExitProcess)

2. 出错退出(自愿,python a.py中a.py不存在)

3. 严重错误(非自愿,执行非法指令,如引用不存在的内存,1/0等,可以捕捉异常,try...except...)

4. 被其他进程杀死

进程的层次结构:

无论是在UNIX还是在windows,进程只有一个父进程,但是

1. 在UNIX中所有的进程,都是以init进程为根,组成树形结构。父子进程共同组成一个进程组,这样,当从键盘发出一个信号时,该信号被送给当前与键盘相关的进程组中的所有成员。

2. 在windows中,没有进程层次的概念,所有的进程都是地位相同的,唯一类似于进程层次的暗示,是在创建进程时,父进程得到一个特别的令牌(称为句柄),该句柄可以用来控制子进程,但是父进程有权把该句柄传给其他子进程,这样就没有层次了。

进程的状态:

就绪状态    、运行状态、阻塞状态 (在进程被创建至死亡之间会在这三种状态之间轮转)

 

python使用进程的类的使用(multiprocessing)

python中的多线程无法利用多核优势,如果想要充分地使用多核CPU的资源(os.cpu_count()查看),在python中大部分情况需要使用多进程。Python提供了multiprocessing。multiprocessing模块用来开启子进程,并在子进程中执行我们定制的任务(比如函数),该模块与多线程模块threading的编程接口类似。multiprocessing模块的功能众多:支持子进程、通信和共享数据、执行不同形式的同步,提供了Process、Queue、Pipe、Lock等组件。 需要再次强调的一点是:与线程不同,进程没有任何共享状态,进程修改的数据,改动仅限于该进程内。

1创建第一个进程

from multiprocessing import Process,current_process


n = 100
def foo(name,age):
    print("子进程:",current_process()) #获取当前进程名
    print("name: %s age:%s" %(name,age))
    global n #将n声明为全局变量
    n = 10
    print("变量n:%s\n子进程结束" %n)


#windows下必须有这一行,因为windows下,创建一个进程会复制整个py文件。
#如果没有该句将会导致循环创建进程
if __name__ == '__main__':
    #创建一个进程对象
    print("主进程开始执行")
    #tarfet = 传入一个函数名 或者一个对象
    #arges :传入一个元组包含传入函数或者对象的参数,(按位置参数传参)
    #kwargs :同上 ,但按照关键字参数传参
    #name :给进程起名字
    subprocess = Process(target=foo,args=("duke",19),name="子进程1")
    subprocess.start() #启动一个进程
    subprocess.join() #等待子进程执行结束
    print(n) #==>100 进程之间是物理隔绝,值不能被直接共享
    print("主进程执行结束")

"""
主进程开始执行
子进程: <Process(子进程1, started)>
name: duke age:19
变量n:10
子进程结束
100
主进程执行结束"""

自定义一个进程

from multiprocessing import Process

def foo(name,age):
    print("name %s age %s" %(name,age))


class Myself_Process(Process):
    def __init__(self,func,args,name=""):
        Process.__init__(self)
        self.name = name
        self.func = func
        self.args = args

    def run(self):
        print("my name is %s" %self.name)
        self.func(*self.args)

if __name__ == '__main__':
    process1 = Myself_Process(foo,("duke",18),name="自定义进程1")
    process1.start()
    process2 = Process(target=foo,args=("duke",18))
    process2.start()
    #启动进程就相当于在运行run,自定义进程,就是在自定义run和__init__
    """
    my name is 自定义进程1
    name duke age 18
    name duke age 18"""

守护进程

from multiprocessing import Process
import time
def foo1():
    print("守护进程开始")
    print("守护进程即将进入睡眠状态")
    time.sleep(3) #模拟I/O操作 切走CPU
    print("守护进程运行结束")

def foo2():
    print("非守护进程开始")
    print("非守护进程即将进入睡眠状态")
    time.sleep(1) #模拟I/O操作 切走CPU
    print("非守护进程运行结束")

if __name__ == '__main__':
    print("主进程运行")
    #守护进程会在主进程运行结束之后被强行干死
    daemon_process = Process(target=foo1)
    #须在start之前设定 否则无效
    #进程之间是并行的
    daemon_process.daemon =True #默认False,若改为True则表示该进程是守护进程
    non_daemon_process = Process(target=foo2)
    daemon_process.start()
    non_daemon_process.start()
    non_daemon_process.join() #等待非守护进程执行完毕,卡主的是主进程
    print("主进程运行完毕")

"""
主进程运行
守护进程开始
守护进程即将进入睡眠状态
非守护进程开始
非守护进程即将进入睡眠状态
非守护进程运行结束
主进程运行完毕"""

为什么要有锁?  ==>为了保证数据安全,防止多个进程同时对一个数据同时进写操作。

 

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值