进程:程序正在执行的过程,就是一个正在执行的任务,而负责执行任务的就是cpu

操作系统:操作系统就是一个协调、管理和控制计算机硬件资源和软件资源的控制程序。

操作系统的作用:

1:隐藏丑陋复杂的硬件接口,提供良好的抽象接口

2:管理、调度进程,并且将多个进程对硬件的竞争变得有序。

多道技术产生的背景:针对单核,实现并发。

多道技术:多道技术中的多道指的是多个程序,多道技术的实现是为了解决多个程序竞争或者说共享同一个资源(比如cpu)的有序调度问题,解决方式即多路复用,多路复用分为时间上的复用和空间上的复用。,

时间复用:当一个程序在等待I/O时,另一个程序可以使用cpu。提高CPU的利用率。

空间复用:同一时间内存可以缓存更多的程序。

进程

主进程和子进程的关系

关于资源:子进程得到的是除了代码段是与父进程共享的意外,其他所有的都是得到父进程的一个副本,子进程的所有资源都继承父进程,得到父进程资源的副本,既然为副本,也就是说,二者并不共享地址空间。,两个是单独的进程,继承了以后二者就没有什么关联了,子进程单独运行。(采用写时复制技术)
关于文件描述符:继承父进程的文件描述符时,相当于调用了dup函数,父子进程共享文件表项,即共同操作同一个文件,一个进程修改了文件,另一个进程也知道此文件被修改了。

子进程回收机制:进程由谁开,由谁回收,等子程序完成后,才由父进程回收

创建进程的方法

方法一:利用subprocess 模块,具体方法见网络编程模块。subprocess模块有很大的局限性。) 我们总是让subprocess运行外部的程序,而不是运行一个Python脚本内部编写的函数。2) 进程间只通过管道进行文本交流。以上限制了我们将subprocess包应用到更广泛的多进程任务。

方法二:利用multiprocessing模块,这个模块叫多进行模块管理包,multiprocessing中的Process中的类可以创建一个子进程。

multiprocessing.Process(group=None, target=None, name=None, args=(), kwargs={})
一般需要指定的参数为target,表示为一个函数,这个函数必须是可调用的,
args表示为target的参数,是一个元组的格式。注意在只有一个参数的时候,必须写上逗号,表示为一个tuple
kwargs表示为target的参数,是一个字典的格式。

注意:在Windows系统中开子进程的代码必须要写在if __name__="__main__" 下。mac笔记本不需要因为这两种系统开启子进程的方式不一样

范例

from multiprocessing import Process
import time
def task(name):
    print("%s is runing"%name)
    time.sleep(2)
    print("%s is done"%name)
if __name__=="__main__":
    p=Process(target=task,args=("egon",))
    p.start()#只是给操作系统发了个信号,让操作系统开进程(同时开辟一块内存空间,拷贝父进程的地址空间)
    print("你好,中国")

结果:

你好,中国
egon is runing
egon is done

子进程回收机制:进程由谁开,由谁回收,等子程序完成后,才由父进程回收

p.start()#只是给操作系统发了个信号,让操作系统开一个进程(同时开辟一块内存空间,拷贝父进程的地址空间),同时我们还要知道start方法是一个异步非阻塞,
因为当执行start方法的时候,并不会阻塞当前进程去等待子进程执行完,
而是会继续执行主进程的代码 p.join() :#阻塞当前进程,直到调用join方法的那个进程执行完,再继续执行当前进程。也就是说主进程等子进程完了,自己再进行进程。join()方法是一个同步阻塞 p.pid #子进程id p.terminate() #强制结束进程,这个方法不能自己杀死自己 p.is_alive() #查看该进程是否活着 # 进程自杀 import os import signal os.kill(os.getpid(), signal.SIGKILL)

 

 python代码由python解释器解释运行,你启用的python进程其实是运用了python exe的进行。

os .getppid()查看父进程的ID

os.getpid()获取当前的进程的ID。

方法三:

from multiprocessing import Process


class MyProcess(Process):
    def __init__(self, n):
        self.n = n
        super(MyProcess, self).__init__()  # 使用父类的方法才能传参

    def run(self):
        """一定要有这个函数"""
        print(self.n)
        print(os.getppid(), os.getpid())


print("主进程", os.getppid(), os.getpid())
my = MyProcess("小红")
my.start()

结果:

主进程 241 6452
小红
6452 6454

进程必须要知道的事情

 1.进程之间内存相互隔离

举例

from multiprocessing import Process
n=1
def f():
global n
n=13
if __name__ == '__main__':
p =Process(target=f)
p.start()
p.join()
print(n)

结果:

 1

结论:子进程不能修改主进程的变量,用global的作用就是看是否会修改全局变量,因为在单进程中可以修改。

2.子进程用主进程的值来作为自己的初始值。

n=1
def f():
    print(n)
if __name__ == '__main__':
p =Process(target=f)
p.start()

 

结果:

1
1

3.不能获得子进程的返回值,因为进程之间是隔离的 

创建并发进程服务器

进程之间的通信(IPC)

由于我们知道进程之间内存是隔离的,但是可以通过别的方法实现进程间的通信

大体有两个方面:

  1. 基于文件 适合于同一台机器上多进程进行通信.基于socket的文件级别的通信
  2. 基于网络 消息中间件(redis,rabbitmq,memcach)
以下是基于文件的实现的进程之间的通信
1.消息队列 from multiprocessing import Queue ,一个进程向队列里放东西,另一个进程向队列中拿东西
  特点:
  1. 数据安全.因为管道加锁
  2. 可以实现进程之间的通信
  3. 先进先出

实现原理:管道+加锁

2.管道是一种半双工的通信方式,管道是指用于连接一个读进程和一个写进程以实现她们之间通信的一个文件。写进程将数据以字符流的形式放入管道,读进程则从管道中接收数据。要实现双向通信必须要创建两个管道.数据不安全,需要加锁
 

第一: 队列

在进程中引用队列的方式:  

from multiprocessing import Queue

在线程中引用队列的方式:

import queue

 

put:放数据,Queue.put( )默认有block=True和timeout两个参数。当block=True时,写入是阻塞式的,阻塞时间由timeout确定。当队列q被(其他线程)写满后,这段代码就会阻塞,直至其他线程取走数据。Queue.put()方法加上 block=False 的参数,即可解决这个隐蔽的问题。但要注意,非阻塞方式写队列,当队列满时会抛出 exception Queue.Full 的异常

get:取数据(默认阻塞),Queue.get([block[, timeout]])获取队列,timeout等待时间
————————————————
版权声明:本文为CSDN博主「brucewong0516」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/brucewong0516/article/details/85796073

举例子:

from multiprocessing import Process,Queue
import os,time,random
def write(q):
    """
    一个进程往队列中放东西
    :param q: 
    :return: 
    """
    for value in ["A","B","C"]:
        print('put %s to queue...'%value)
        q.put(value)#往里面放东西
        time.sleep(random.random())
def read(q):
    """
    另一个进程从队列中拿数据
    :param q: 
    :return: 
    """
    while True:
        if not q.empty():
            value=q.get(True)#从里面拿东西
            print('GET %s from queue'%value)
            time.sleep(random.random())
        else:
            break
if __name__ == '__main__':
    q=Queue()#可以不设置大小,受限于内存的大小
    pw=Process(target=write,args=(q,))
    pr=Process(target=read,args=(q,))
    pw.start()
    pw.join()
    pr.start()
    pr.join()
    print('所有的数据都拿完了')

结果:

网络编程并发 多进程 进程池,互斥锁,信号量,IO模型
put A to queue...
put B to queue...
put C to queue...
GET A from queue
GET B from queue
GET C from queue
所有的数据都完了
View Code

相关文章: