并发编程

并发编程

  • 什么是并发编程

    并发指的是多个任务同时被执行,并发编程指的是编写支持多任务的应用程序

并发编程中重要的概念*******

1串行:自上而下顺序执行

2并发:多个任务同时执行,但是本质上是在不同进程间切换执行,由于速度快所以感觉是同时进行的

3并行:是真正的同时进行,必须具备的是多核CPU,有几个核心就能并行几个任务,当任务数量超过核心数,任务进行并发

遇到的状态:

阻塞和非阻塞可以用来描述执行任务的方式

1阻塞:程序遇到了IO操作,无法继续执行代码一种

  • input()默认是一个阻塞操作

2非阻塞:程序没有遇到IO操作的一种

  • 我们可以用一些手段将阻塞的操作变成非阻塞的操作,非阻塞的socket

一个进程的三种状态:1阻塞,2运行,3就绪

并发和串行

目前程序存在的问题

默认执行方式是串行,所谓串行,即程序自上而下运行,一行行代码执行,必须把当前任务执行完才进行下面的任务,不管花多长时间

e.g.

  • 在tcp服务器中,如果正在进行通讯循环无法处理其他客户的要求
  • 在硬盘中读取大文件
  • 执行input

学习并发的目的

编写可以同时执行多个任务的程序,来提高效率

​ 串行和并发都是程序处理任务的方式

多道技术是

实现原理:---------------------有了多道技术,计算机就可以同时并发处理多个任务

1,空间复用:

​ 同一时间,加载多个任务到内存中,多个进程之间内存区域需要相互隔离,这个隔离是物理层面的隔离,目的是保证数据的安全

2,时间的复用:

​ 操作系统会在多个进程之间按做切换执行,切换任务的两个情况

  • 1当一个进程遇到了IO操作,会自动切换
  • 2当一个任务执行时间超过阈值会强制i切换

在切换前必须保存状态,以便恢复执行----频繁切换是需要消耗资源的

当所有任务都没有io操作时,切换执行效率反而降低,为了保证并发执行,必须牺牲效率

进程

什么是进程

1,进程指的是正在运行的程序,是一系列过程的统称,也是操作系统在调度和进行资源分配的基本单位

2,进程怎么来的:当程序从硬盘读入内存,进程就产生了

3,多进程的概念:多个程序同一时间被装入内存并且执行(一个程序可以产生多个进程,比如说运行多个qq程序)

进程是实现并发的一种方式-------涉及到操作系统,因为这个概念来自于操作系统,没有操作系统就没有进程

  • 多进程实现原理就是操作系统调度进程的原理

进程的创建和销毁

创建:

  • 用户的交互式请求,鼠标双击
  • 由一个正在运行的程序,调用了开启进程的接口,例如 subprosess
  • 一个批作业的开始
  • 系统的初始化

销毁:

  • 任务完成,自愿退出
  • 强制退出,taskkill kill(非自愿)
  • 程序遇到了异常
  • 严重的的错误,访问了不该访问的内存

PID和PPIFD

PID是当前进程的编号

PPID是父进程的编号

在运行py文件时其实是运行的python解释器

访问PID  PPID
import os
os.getpid()
os.getppid()

python如何使用多进程

创建子进程的方式

1导入multiprocessing 中的Process类 实例化这个类,指定要执行的任务target

import os
from multiprocessing import Process
"""process 就表示进程"""
def task():
    print("this is sub process")
    print("sub process id %s"% os.getpid())
if __name__=='__main__'
	"开启进程的代码必须是放在__main__判断下面"
    #实例化一个进程对象,并制定他要做的事情,函数来指定
    p=Process(target =task)
    p.start()     #给操作系统发送信息,让其开启进程
    print("this is parent process")
    print('parent process is %s'% os.getpid())
    print('over')

widows 回到如父进程的代码,从头执行一遍,来获取需要处理的任务

所以在编写代码时如果是windows一定要开启进程的代码放在main判断中

linux可以不放

2导入multiprocessing中的Process类,覆盖run的方法,将要执行的任务放在run中,开启进程时会自动执行该函数

from multiprocessing import Process
import os
class Downloader(Process)
	#def__init__(self,url,size,name):
    #	super().__init__()
    #	self.url =url
    #	self.size =size
    #	self.name=name
    
    def run(self):
        print(os.getpid())
        pass
    
if __name__=='__main__'
	m=Downloader()
    m.start()
    print("parent over",os.getpid())
    
	

3进程之间内存相互隔离

from multiprocessing import Process
import os,time
a=257

def task():
    global a
    #print("2",a,id(a))
    a=200
    
if __name__=='__main__'
	p=Process(target=task)
    p.start()  #像操作系统发送指令
    
    time.sleep(4)
    print(a)

4join函数

from multiprocessing import Process
import time
def task1(name):
    for i in range(1000):
        print("%s run"% name)
def task2(name):
    for i in range(100):
        print("%s run"% name)
        
if __name__=='__main__':   #args 是给子进程传参的参数,必须是元组
    p1=Process(target=task1,arg=("p1",))
    p1.start()  #向操作系统发送指令
    #p1.join()  #让主进程 等待子进程执行完毕再急促执行
    
    p2 =Process(target=task2,args("p2",0))
    p2.start()
    
    
    p2.join()
    p1.join()
    
    #需要达到的效果是 必须保证两个子进程是并发执行的,并且over一定是在所有执行完毕后才执行的
    print('over')
    
    

案例:join的使用

#join使用
from multiprocessing import Process
import time
def task1(name):
    for i in range(10):
        print("% run "% name)
        
if __name__=='__main__':  #args 是给子进程传递额参数,必须是元组
    ps =[]
    for i  in range(10):
        p=Process(target=task1,arg=(i,))
        p.start()
        ps.append(p)
        
    #换个join下
    for i in ps:
        i.join()
        
    print('over')
    

进程对象的常用属性:

if__name__=='__main__':
    p=Process(target=task,name="老司机进程")
    p.start()
    p.join()
    print(p.name)
    p.daemon  #守护进程
    print(p.exitcode)  #获取进程的退出码   就是exit()函数中传入的值
    print(p.is_alive())#查看进程是否存活
    print('zi',p.pid)  #获取进程id
    print(os.getpid())
    p.terminate()      #终止进程  与strat 相同的是,不会立即终止,因为操作系统有很多事要做
    

僵尸进程和孤儿进程

孤儿进程:当父进程已经结束了,而子进程还在运行,子进程就变成了孤儿进程,尤其是存在的重要性,没有不良影响

僵尸进程:当一个进程结束了,它任然还有一些数据存在,此时称之为

在linux机制中,有这么一个机制,父进程无论什么时候都可以获取到子进程的一些数据

子进程任务完成后,确实结束了但是任然保留一些数据,目的是为了让父进程能够获取这些信息

linux中,可以调用waitpid来彻底清除子进程的残留信息

python中,已经封装处理了僵尸进程操作,无需关心

原文地址:https://www.cnblogs.com/zhuyuanying123--/p/11122701.html