网络并发编程

发布于:2023-01-04 ⋅ 阅读:(384) ⋅ 点赞:(0)

网络并发编程的本质就是为了提升CPU的工作效率.

目录

操作系统发展史

多道技术

进程理论

进程的并行与并发

进程三状态

同步与异步

阻塞与非阻塞

同步异步与阻塞非阻塞

创建进/线程的两种方式

join方法

进程间默认数据隔离

IPC机制

生产者消费者模型

查找进/线程相关方法

守护进/线程

僵尸进程与孤儿进程



操作系统发展史


计算机的三大核心硬件是: CPU, 内存, 硬盘. 其中CPU是整个计算机执行效率的核心

操作系统经历了三个时代;
1.穿孔卡片时代 
        CPU的利用率非常低, 优点是一个人独占计算机.
2.联机批处理系统
        缩短了录入数据的时间,提升了CPU利用率
3.脱机批处理系统
        是现代计算机的雏形, 提升了CPU的利用率
        


多道技术


其前提是一个CPU
单道技术是所有的程序排队执行, 总耗时是所有程序耗时之和.
多道技术是计算机利用空闲时间提前准备好一些数据,提高效率, 总耗时较短.

多道技术的特点是切换+保存状态
1.CPU在两种状态下会切换去执行其他操作
        1.程序自身进入IO操作[IO操作: 输入输出操作, 获取用户输入, 读取文件,保存文件,time.sleep()等
        2. 程序长时间占用CPU.
2. 保存状态  每次切换之前都要记录下当前执行的状态,之后切回来基于当前状态继续执行.

进程理论


进程: 正在被运行的程序
进程的调度算法:
1.先来先服务  >>> 对耗时较短的程序不友好
2.短作业优先调度  >>> 对耗时长的程序不友好
3.时间片轮转法+多级反馈队列
        将固定的时间均分成很多份,所有的程序来了都平分一份 >>> 分配多次之后如果还有程序需要运行, 则将其分到下一层 >>> 越往下表示程序总耗时越长,每次分的时间片越多则优先级越低. 

进程的并行与并发


并行: 多个进程同时执行 , 需要有多个CPU
并发:多个进程看上去像是同时执行就可以称之为并发,  单个CPU完全可以实现并发的效果, 如果是并行那么肯定也属于并发.  >>>> 描述一个网站很厉害能同时服务很多人>>>> 这个网站能够支持14亿并发量(高并发)  >>> 国内最厉害的网站>>>12306

进程三状态


就绪态: 所有程序被运行期都要经过就绪态(准备状态)
运行态:运行过程中如果出现了IO操作,则进入阻塞态, 如果时间片段用完则继续进入就绪态
阻塞态: 想要进入运行态就必须经过就绪态

同步和异步


用于描述人物的提状态
同步: 提交完任务后原地等待任务结束, 不做任何事.
异步: 提交完任务后不原地等待直接去做其他事情, 有了结果自动提醒. 

阻塞与非阻塞


用于描述进程的执行状态
阻塞为阻塞态
非阻塞为就绪态或者运行态

同步异步与阻塞非阻塞


同步阻塞: 排队,并且在队伍中做什么都不做
同步非阻塞; 排队, 在排队过程中做一些事情
异步阻塞: 取号, 在旁边等待被叫号,期间什么也不做
异步非阻塞: 取号,在旁边等待叫号,期间做想做的事.
其中异步非阻塞状态下 CPU利用率最高. 

创建进程的两种方式


1.双击桌面程序图标
2.代码创建

from multiprocessing import Process
import time


def task(name):
    print(f'{name}开始运行')
    time.sleep(3)
    print(f'{name}运行结束')

if __name__ == '__main__':
    p = Process(target=task,args=('lili',))  # 创建一个进程对象
    p.start()  # 告诉操作系统创建一个进程(异步操作)
    # task('lili')   # 普普通通的函数调用是 同步操作
    print('主进程')  

""" 创建进程的代码在不同的操作系统中, 底层原理有区别. 
在Windows中, 创建进程类似于导入模块
if __name__ == '__main__': 启动脚本在MAC,LINUX中创建进程类似于直接copy,不需要启动脚本, 但是为了兼容性, 也可以使用."""`

from multiprocessing import Process
import time

class MyProcess(Process):
    def __init__(self,name):
        super().__init__()
        self.name = name

    def run(self):
        print(f'{self.name}开始运行')
        time.sleep(3)
        print(f'{self.name}结束运行')

if __name__ == '__main__':
    obj = MyProcess('lili')
    obj.start()
    print('主进程')

**创建进程的方式和创建现成的方式一致.**  

同一进程下线程间数据共享


我们将进程比作车间, 线程比作流水线, 那么同意车间内的资源是可以被不同流水线间共享的.

from threading import Thread

money = 1000


def func():
    global money
    money = 666


t = Thread(target=func)
t.start()
t.join()  # 确保线程运行完毕 再查找money 结果更具有说服性
print(money)


 

进程join方法


join主进程等待子进程运行结束之后在运行
>>> 直接在主进程代码里添加time.sleep()是不合理的, 因为无法准确把我子进程的执行时间
使用join方法就会变得合理很多

from multiprocessing import Process
import time

def task(name):
    print(f'{name}正在运行')
    time.sleep(3)
    print(f'{name}结束运行')

if __name__ == '__main__':
    p1 = Process(target=task,args=('lili',1))
    p2 = Process(target=task,args=('pop',2))
    p3 = Process(target=task,args=('kim',3))
    start_time = time.time()
    p1.start()
    p2.start()
    p3.start()
    p1.join()
    p2.join()
    p3.join()
    end_time = time.time() - start_time
    print('总耗时:%s' %end_time)
    print('主进程')

线程join方法


主线程等到子线程运行结束之后再运行
 

from threading import Thread
import time

def task():
    print('正在执行')
    time.sleep(3)
    print('运行结束')


t = Thread(target=task)
t.start()
t.join()
print('主线程')


 

进程间默认数据隔离


多个进程数据彼此之间默认相互隔离
如果真的要交互,需要借助于'管道'或者'队列'

 from multiprocessing import Process
 ​money = 100
 ​​def task():    
     global money    
     money = 666    
     print('子进程打印的money', money)
 ​​if __name__ == '__main__':   
     p = Process(target=task)    
     p.start()    
     p.join()    
     print('父进程打印的money', money)


IPC机制


1.主进程与子进程通信
2.子进程与子进程通信

from multiprocessing import Queue,Process

def procedure(q):
    q.put('子进程procedure往队列里添加了数据')


def consumer(q):
    print('子进程consumer从队列里获取数据',q.get())


if __name__ == '__main__':
    q = Queue()  # 在主进程中产生q对象,确保所有的子进程使用的是相同的q
    p1 = Process(target=procedure, args=(q,))
    p2 = Process(target=consumer, args=(q,))
    p1.start()
    p2.start()
    print('主进程')



生产者消费者模型


生产者: 产生数据
消费者: 处理数据


进程相关方法


查看进程号

    from multiprocessing import current_process
    import os
    current_process().pid
    os.getpid()
    os.getppid()

销毁子进程
    p1.terminate()
判断进程是否存活
    p1.is_alive()


线程相关方法


1.进程号
    同一个进程下开设的多个线程拥有相同的进程号
2.线程名
    from threading import Thread, current_thread
    current_thread().name
     主:MainThread    子:Thread-N
3.进程下的线程数
    active_count()

守护进程


伴随着守护对象的存活而存活 死亡而死亡

from multiprocessing import Process
import time


def task(name):
    print('用户a:%s存活' % name)
    time.sleep(3)
    print('用户a:%s消失' % name)


if __name__ == '__main__':
    p = Process(target=task, args=('基佬',))
    # p.daemon = True  # 将子进程设置为守护进程:主进程代码结束 子进程立刻结束
    p.start()
    p.daemon = True  # 必须在start之前执行
    print('主进程结束!!!')


 

守护线程


守护线程伴随着被守护的线程的结束而结束

from threading import Thread
import time

def task():
    print('子线程运行task函数')
    time.sleep(3)
    print('子线程运行task结束')


t = Thread(target=task)
# t.daemon = True
t.start()
# t.daemon = True
print('主线程')


进程下所有的非守护线程结束 主线程(主进程)才能真正结束!!!

僵尸进程与孤儿进程


僵尸进程: 进程已经运行结束,单数相关资源并没有完全清空, 需要父进程参与回收
孤儿进程: 父进程意外死亡,子进程正常运行,操作系统会自动回收相关资源.

本文全是理论, 只为科普一些基本的概念. 

 

 

本文含有隐藏内容,请 开通VIP 后查看

网站公告

今日签到

点亮在社区的每一天
去签到