并发编程(进程篇,未完待续)

一、socketserver模块

  • 该模块用于在网络编程中实现并发效果
  • 下面模拟一个客户输入信息然后服务端返回信息大写的并发效果

1.服务端

import socketserver

#基于tcp协议
'''
self.request=>conn
'''
class MyRequestHandle(socketserver.BaseRequestHandler):
    def handle(self):
    	print(self.client_address)
        while True:
            try:
                msg = self.requset.recv(1024)
                if len(msg) == 0: break
                self.request.send(msg.upper())
            except Exception:
                break
        self.request.close()

#服务端应该做两件事情
#第一件事:循环地从半链接池中取出链接 请求与其建立双向链接
#第二件事:拿到链接对象,与其进行通信循环

s=socketserver.TCPServer(('127.0.0.1',8880),MyRequestHandle)
s.serve_forever()

2.客户端1

import socket


client = socket(AF_INET,SOCK_STREAM)
cliene.connect(('127.0.0.1',8880))

while True:
    msg = input('请输入命令:').strip()
    if len(msg) == 0: continue
    client.send(msg.encode('utf-8'))
    
    res = client.rece(1024)
    print(res.decode('utf-8'))

3.客户端2

import socket


client = socket(AF_INET,SOCK_STREAM)
cliene.connect(('127.0.0.1',8880))

while True:
    msg = input('请输入命令:').strip()
    if len(msg) == 0: continue
    client.send(msg.encode('utf-8'))
    
    res = client.rece(1024)
    print(res.decode('utf-8'))

4.效果截图

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

二、一些重要知识

  • 操作系统的发展历史是围绕提高CPU运行效率展开的
  • 进程:正在运行的程序
  • 程序:代码
  • 多道技术:
    • 目的:单核实现并发
    • 主要是实现程序对计算机的空间复用和时间复用
    • 空间复用:多个程序共用一计算机硬件系统
    • 时间复用:保存程序的运行状态+切换程序
      +切换分为两种情况:
      1.程序遇到IO操作
      2.程序运行时间过长
  • 并行和并发
    • 并发:看起来像同时在做不同事情
    • 并行:同时做不同的事情
  • 进程的调度
    • 先来先服务调度算法
    • 短作业优先调度算法
    • 时间片轮转法+多级反馈队列
  • 进程三状态
    +就绪态、运行态、阻塞态
    +程序要进入运行态前必然经历就绪态
    +阻塞态就是遇到IO等操作会进入阻塞态
  • 同步&异步、阻塞&非阻塞
    • 同步异步是针对任务提交而言
    • 阻塞非阻塞是针对程序运行状态而言
    • 效率最高的就是异步非阻塞

三、创建进程的两种方式和join方法

1.非程序方面开启进程

随便双击几个应用,几个应用同时运行就是开了多个进程

2.程序层面开启进程

创建进程的两种方式
第一种应用颇多

3.join方法

  • 简单来说就是让主进程等着子进程运行完之后,主程序再往下运行
  • 我们来做一个程序时间测试的小程序
from multiprocessing import Process
import time

def task(i):
    time.sleep(i)

if __name__ == '__main__':
    pro_lis = []
    start = time.time()
    # 创建三个进程
    for i in range(3):
        p = Process(target=task,args=(i,))
        pro_lis.append(p)

    # 启动三个进程
    for pro in pro_lis:
        pro.start()
    print(time.time()-start)

运行结果:0.0258924961090087

尽管这并不是程序最终运行时间,实际上时间应该是2s多,但结合下面例子你足以看出join的用法,有点并发变串行的感觉。

from multiprocessing import Process
import time

def task(i):
    time.sleep(i)

if __name__ == '__main__':
    pro_lis = []
    start = time.time()
    # 创建三个进程
    for i in range(3):
        p = Process(target=task,args=(i,))
        pro_lis.append(p)
    
    # 启动三个进程
    for pro in pro_lis:
        pro.start()
        pro.join()
    print(time.time()-start)

结果:4.735849142074585

四、进程间数据隔离

  • 这是一个结论,我们来验证一下
from multiprocessing import Process


money = 100


def task():
    global money  # 局部修改全局
    money = 666
    print('子',money)


if __name__ == '__main__':
    p = Process(target=task)
    p.start()
    p.join()
    print(money)

Result:

666
100

五、进程对象及其他方法

  • p.terminate() # 杀死当前进程
  • p.is_alive() # 判断当前进程是否存活
  • os.getpid() 获得进程号 等同于current_process().pid
    • 补充:Windows:cmd里 tasklist查看所有进程
    • tasklist | find “关键字” 可以对结果进行过滤,即单独获取某个程序的进程
      +os.getppid() #获得父进程号
from multiprocessing import Process, current_process
import time
import os


def task():
    print('%s is running'%current_process().pid)  # 查看当前进程的进程号
    print('%s is running'%os.getpid())  # 查看当前进程的进程号
    print('子进程的主进程号%s'%os.getppid())  # 查看当前进程的进程号
    time.sleep(30)


if __name__ == '__main__':
    p = Process(target=task)
    p.start()
    p.terminate()  # 杀死当前进程
    # 是告诉操作系统帮你去杀死当前进程 但是需要一定的时间 而代码的运行速度极快
    time.sleep(0.1)
    print(p.is_alive())  # 判断当前进程是否存活
    """
    一般情况下我们会默认将
    存储布尔值的变量名
    和返回的结果是布尔值的方法名
    都起成以is_开头
    """
    print('主')
    print('主',current_process().pid)
    print('主',os.getpid())
    print('主主',os.getppid())  # 获取父进程的pid号





结果:

False
主
主 92569256
主主 18360

六、僵尸进程、孤儿进程、守护进程

  • 僵尸进程指的是该进程结束后没死完,会保留一段时间,供父进程查看这个进程的进程号、运行时间等信息,当父进程存在一直在产生子进程的时候,无限开辟内存空间,这是不好的

  • 孤儿进程是子进程存活,而父进程死亡,操作系统有个机制会解决孤儿进程回收问题

  • 守护线程是跟着操作系统同生共死的进程

  • p.daemon = True # 将进程p设置成守护进程

  • 这一句一定要放在start方法上面才有效否则会直接报错

一个例子:古代皇帝驾崩其身边太监也必须gameover

from multiprocessing import Process
import time


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


if __name__ == '__main__':
    p = Process(target=task,args=('太监',))
    # p = Process(target=task,kwargs={'name':'egon'})
    p.daemon = True  # 将进程p设置成守护进程  这一句一定要放在start方法上面才有效否则会直接报错
    p.start()
    print('皇帝寿终正寝')

结果:注意太监。。

皇帝寿终正寝

注释守护进程之后

from multiprocessing import Process
import time


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


if __name__ == '__main__':
    p = Process(target=task,args=('太监',))
    # p = Process(target=task,kwargs={'name':'egon'})
    # p.daemon = True  # 将进程p设置成守护进程  这一句一定要放在start方法上面才有效否则会直接报错
    p.start()
    print('皇帝寿终正寝')

结果:

皇帝寿终正寝
太监总管正在活着
太监总管正在死亡

七、互斥锁

八、队列&消息队列、IPC机制

九、生产者消费者模型

猜你喜欢

转载自blog.csdn.net/qq_49821869/article/details/112910543