python-进程

一、进程

  1. 什么是并发编程:并发指的是多个任务同时被执行,在之前的TCP通讯中,服务器在建立连接后需要一个循环来与客户端循环的收发数据,但服务器并不知道客户端什么时候会发来数据,导致没有数据时服务器进入了一个等待状态,此时其他客户端也无法连接服务器,很明显这是不合理的,学习并发编程就是要找到一种方案,让一个程序中多个任务可以同时被处理

  2. 什么是进程:进程指的是正在运行的程序,是一系列过程的统称,也是操作系统在调度和进行资源分配的基本单位。进程是实现并发的一种方式,在学习并发编程之前要先了解进程的基本概念以及多进程的实现原理,这就不得不提到操作系统了,因为进程这个概念来自于操作系统,没有操作系统就没有进程

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

  4. 空间上的复用:将内存分为几个部分,每个部分放入一个程序,这样同一时间内存中就有了多道程序

  5. 时间上的复用:当一个程序在等待I/O时,另一个程序可以使用cpu,如果内存中可以同时存放足够多的作业,则cpu的利用率可以接近100%,(操作系统采用了多道技术后,可以控制进程的切换,或者说进程之间去争抢cpu的执行权限。这种切换不仅会在一个进程遇到io时进行,一个进程占用cpu时间过长也会切换,或者说被操作系统夺走cpu的执行权限)

  6. 空间上的复用最大的问题是:程序之间的内存必须分割,这种分割需要在硬件层面实现,由操作系统控制。如果内存彼此不分割,则一个程序可以访问另外一个程序的内存,首先丧失的是安全性,比如你的qq程序可以访问操作系统的内存,这意味着你的qq可以拿到操作系统的所有权限。

    其次丧失的是稳定性,某个程序崩溃时有可能把别的程序的内存也给回收了,比方说把操作系统的内存给回收了,则操作系统崩溃。

  7. 进程与程序:进程是正在运行的程序,程序是程序员编写的一堆代码,也就是一堆字符,当这堆代码被系统加载到内存中并执行时,就有了进程。

    例如:生活中我们会按照菜谱来做菜,那么菜谱就是程序,做菜的工程就是进程

    测试:

import time
while True:
    time.sleep(1)

多次运行该文件,就会产生多个python.exe进程,可以通过cmd中的tasklist来查看运行的程序

二、进程PID与PPID

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

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

    测试:

    cmd中可以使用tasklist 用于查看所有的进程信息

    taskkill /f /pid pid 该命令可以用于结束指定进程

import os

import time
while True:
    time.sleep(0.5)
    print("hahaha")
    print("self", os.getpid()) #获取自己的进程id
    print("parent",os.getppid())  #获取父进程的id

三、并发与并行 阻塞与非阻塞

  1. 并发:多个事件同时发生了。例如洗衣服和做饭,同时发生了,但本质上是两个任务在切换,给人的感觉是同时在进行,也被称为伪并行

  2. 并行:多个事件都是进行着。例如一个人在写代码另一个人在写书,这两件事件是同时在进行的,要注意的是一个人是无法真正的并行执行任务的,在计算机中单核CPU也是无法真正并行的,之所以单核CPU也能同时运行qq和微信其实就是并发执行

  3. 阻塞与非阻塞:指的是程序的状态。阻塞状态是因为程序遇到了IO操作,或是sleep,导致后续的代码不能被CPU执行。非阻塞与之相反,表示程序正在正常被CPU执行

    进程有三种状态

    就绪态

    运行态

    阻塞态

    在这里插入图片描述

四、开启进程的两种方式

from multiprocessing import Process
import os

def task(name):
    print(name)
    print("self",os.getpid()) #进程id self 5980
    print("parent", os.getppid()) #进程id parent 5324
    print("task run")
# windows 创建子进程时,子进程会将父进程的代码加载一遍,导致重复创建子进程
# 所以一定要将创建子进程的代码放到main的下面
if __name__ == '__main__':
    print("self", os.getpid()) #进程id self 5324
    print("parent", os.getppid()) #进程id parent 1404
    p = Process(target=task, name="这是子进程!",kwargs={"name":"bgon"})  # 创建一个表示进程的对象
    p.start()  # 给操作系统发送通知,要求操作系统开启进程

创建进程的第二种方式:继承Process ,覆盖run方法,在子进程启动以后会自动执行run方法。其优势是可以自定义进程的属性和行为来完成一些额外任务

from multiprocessing import Process

class MyProcess(Process):

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

    # 子类中的方法只有run会被自动执行
    def run(self):
        print("下载文件...." , self.url)
        print(" run run run!")

    def task(self):
        pass

def task():
    print(123)

if __name__ == '__main__':
    p = MyProcess("www.baidu.com/xx.mp4")
    p.start()

五、进程间内存相互独立

from multiprocessing import Process

import time
a = 100

def task():
    global a
    print(id(a))
    a = 0
    print("子进程的",a)

if __name__ == '__main__':
    print(id(a))
    p = Process(target=task)
    p.start() # 给操作系统发送请求后,代码会继续往下运行,至于子进程什么时候创建,什么时候执行都跟当前进程没关系

    time.sleep(1)
    print("自己的",a)
    
#1392212544
#1392212544
#子进程的 0
#自己的 100

六、父进程等待子进程结束

import time
from multiprocessing import Process

def task():
    print("上传文件....")
    time.sleep(3)
    print("上传结束...")

if __name__ == '__main__':
    p = Process(target=task)
    p.start()
    p.join() # 本质上是提高了子进程优先级,当CPU在切换时会优先切子进程
    print("上传文件成功!")
import time
from multiprocessing import Process

def task(num):
    print("我是%s号 进程" % num)
    time.sleep(2)

if __name__ == '__main__':
    start_time = time.time()
    ps = []
    for i in range(10):
        p = Process(target=task,args=(i,))
        p.start()
        ps.append(p)

    for p in ps:
        p.join()

    print(time.time()-start_time)
    print("over")
"""
我是0号 进程
我是1号 进程
我是2号 进程
我是8号 进程
我是3号 进程
我是4号 进程
我是7号 进程
我是5号 进程
我是9号 进程
我是6号 进程
2.685192346572876
over
"""

七、process常用属性

from multiprocessing import  Process

import  time
def task():
    time.sleep(3)
    print("执行完毕!")

if __name__ == '__main__':
    p = Process(target=task,name="alex")
    p.start()
    print(p.name)
    print(p.is_alive()) #判断进程是否存活
    p.terminate() #终止这个进程
    print(p.pid)
    p.daemon #守护进程   

八、孤儿进程与僵尸进程

  1. 孤儿进程:父进程已经终止了,但是自己还在运行,是无害的,孤儿进程会过继给操作系统

  2. 僵尸进程:子进程执行完所有任务,已经终止了,但是还残留了一些信息(进程id,进程名)但是父进程没有去处理这些残留信息,导致残留信息占用系统内存。僵尸进程是有害的,当出现大量的僵尸进程时,会占用系统资源,可以把它的父进程杀掉,僵尸就成了孤儿,操作系统会负责回收数据

    僵尸进程示范:

import  time
from multiprocessing import  Process
def task1():
    print("子进程 run")

if __name__ == '__main__':
    for i in range(10):
        p = Process(target=task1)
        p.start()

    time.sleep(100000)

练习:

1、改写下列程序,分别别实现下述打印效果
from multiprocessing import Process
import time
import random
def task(n):
    time.sleep(random.randint(1, 3))
    print('-------->%s' % n)


if __name__ == '__main__':
    p1 = Process(target=task, args=(1,))
    p2 = Process(target=task, args=(2,))
    p3 = Process(target=task, args=(3,))

    p1.start()
    p2.start()
    p3.start()

    print('-------->4')
效果一:保证最先输出 - ------->4

-------->4
-------->1
-------->3
-------->2
效果二:保证最后输出 - ------->4

-------->2
-------->3
-------->1
-------->4
效果三:保证按顺序输出

-------->1
-------->2
-------->3
-------->4
===========================================
2、判断上述三种效果,哪种属于并发,哪种属于串行?
效果1和效果2属于并发,效果3属于串行
===========================================
3、基于多进程实现并发的套接字通信
   提示:需要在server.bind(('127.0.0.1',8080))之前添加一行
   server.setsockopt(SOL_SOCKET,SO_REUSEADDR,1) # 重用端口号

============================================
4、什么是多道技术,具体实现原理是什么?
多道复用,提高效率。时间复用,遇到io时切换到另一个程序。空间复用,内存中分为多个区域,每个区域时独立的,互不影响。

=============================================
5、CPU在遇到IO或时间过长时会切换,比较两种情况带来的好处与不足
切换可以提高效率,让多个程序同时运行。如果都是纯计算任务,反而降低效率

第一题:

#属于并发
from multiprocessing import Process
import time
import random
def task(n):
    time.sleep(random.randint(1, 3))
    print('-------->%s' % n)


if __name__ == '__main__':
    p1 = Process(target=task, args=(1,))
    p2 = Process(target=task, args=(2,))
    p3 = Process(target=task, args=(3,))

    p1.start()
    p2.start()
    p3.start()

    print('-------->4')
    
==============================================

#属于并发
from multiprocessing import Process
import time
import random

def task(n):
    time.sleep(1)
    print('-------->%s' %n)

if __name__ == '__main__':
    p1=Process(target=task,args=(1,))
    p2=Process(target=task,args=(2,))
    p3=Process(target=task,args=(3,))

    p1.start()
    p2.start()
    p3.start()
    p1.join()
    p2.join()
    p3.join()

    print('-------->4')
    
=============================================

#属于串行
from multiprocessing import Process
import time
import random

def task(n):
    time.sleep(1)
    print('-------->%s' %n)

if __name__ == '__main__':
    p1=Process(target=task,args=(1,))
    p2=Process(target=task,args=(2,))
    p3=Process(target=task,args=(3,))

    p1.start()
    p1.join()
    p2.start()
    p2.join()
    p3.start()
    p3.join()

    print('-------->4')

第三题:

服务端:

from multiprocessing import Process
import socket

server = socket.socket()
server.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) #端口复用

server.bind(("127.0.0.1",8787))
server.listen(5)


def task(client):
    print(client)
    while True:
        try:
            data = client.recv(1024)
            if not data:
                print("客户端已经断开...")
                client.close()
                break
            data = data.decode("utf-8")
            print(data)
            client.send(data.upper().encode("utf-8"))
            # 在子进程中不能使用input来接收输入
            #backmsg = input(">:")

            #client.send(backmsg.encode("utf-8"))

        except Exception as e:
            print("出错啦....", e)
            client.close()
            break

if __name__ == '__main__':
    while True:
        client,addr = server.accept()
        p = Process(target=task,args=(client,))
        p.start()

客户端:

import  socket
c = socket.socket()
c.connect(("127.0.0.1",8787))

while True:
    msg = input(">:").strip()
    if not msg:
        continue
    c.send(msg.encode("utf-8"))

    data = c.recv(1024).decode("utf-8")
    print(data)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值