zoukankan      html  css  js  c++  java
  • 5,线程池,进程池,协程,IO模型

    今日内容:
    1,线程池
    2,进程池
    3,协程
    4,IO 模型


    服务端要满足这三个条件:
    1,24小时不间断的提供服务
    2,能够支持高并发
    3,要有固定的IP地址和端口
    在服务端这个地方会出现阻塞态情况:
    阻塞IO 操作有:
    1,链接循环
    2,通信循环
    单线程实现高并发思路:
    为了更好的提高程序的运行效率,即实现高并发,让服务端同时能够接受多个客户端的消息
    所以一般在服务端会把,连接循环和通信循环封装为两个不同的函数方法,
    这样当一个客户端与服务端进行通信时,服务端的连接循环可以和其他客户端进行连接,
    不要等待,从而提高了效率,可以利用单线程来完成高并发,即来一个客户端就开一个线程,
    每来一个客户端就开一个线程,看上去像高并发!
    案列:
    import socket
    from threading import Thread

    def server1():
    server = socket.socket()
    server.bind(('127.0.0.1', 1688))
    server.listen(5)
    server2(server)

    def task(conn): 通信循环
    while True:
    try:
    data = conn.recv(1024) # 在这里会形成阻塞,等待对客户端发消息过来
    # 不加,就会形成阻塞,一直等待对方发消息过来
    if len(data) == 0:break # 在这里最好把这个条件判断加上,以适用不同的操作系统
    print(data.decode('utf-8'))
    conn.send(data.upper())
    except ConnectionResetError as e:
    print(e)
    break
    conn.close()

    def server2(server): 连接循环
    while True:
    conn, addr = server.accept() # 在这里会形成阻塞,监听是否有客户端过来
    t = Thread(target=task, args=(conn,))
    t.start()
    问题:上面的案例虽然解决了线程高并发的问题,但是但有大量的客户端来访问服务端时,由于开启线程也是需要消耗资源的
    所以但有几亿个用户同时访问时,也架不住量大,也会造成内存溢出,服务器奔溃现象,这是由于硬件性能决定的,
    所以为了防止服务器奔溃,保证数据的安全性,在保证计算机能够承受的范围内,最大限度的利用计算机,
    就引入了池这个概念
    1,什么是池?
    在保证计算机硬件安全的情况下最大限度的利用计算机
    池其实是降低了程序的运行效率 但是保证了计算机硬件的安全
    (硬件的发展跟不上软件的速度)
    2,线程池,
    进程池
    案列:
    import time
    from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor
    # 线程池,在你不传参数的情况下,默认的是当前计算机CPU的个数*5
    pool = ThreadPoolExecutor(5) # 括号内可以传参数,指定线程池的线程个数
    # 只要创建了五个线程,就永远是这五个线程,这五个线程并不会动态创建,动态销毁
    # 好处是节省空间,进程也是如此
    def task(n):
    print(n)
    time.sleep(2)
    #return n*2
    t_list = []
    for i in range(20):
    res = pool.submit(task,i) # submit 的返回值是一个内部Future类产生的对象
    print(res) # 类对象 res.result()它拿到的结果就是task任务的返回值
    print(res.result()) # 结果为 0 None 1 None 2 None 3 None...19 None
    1,将结果变为串行 2,结果为None (在这里res.result()拿到得是task这个任务的返回结果
    原地等待任务的返回结果 ,即同步,如果这样调就会将并发变为串行
    结果为None,是因为task任务的返回结果为None,所以为空,如果加上return n*2,那就不为空
    t_list.append(res)
    pool.shutdown() # 1,关闭池子,即20个线程提交完毕,立马关闭池子,就像关门打狗一样
    # 2,等待池子里面所有的任务完成之后才会继续向下执行
    for p in t_list:
    print('>>>>>对象',p.result(),p)
    # 结果是乱的:14
    # >>>>>对象 None <Future at 0x2aa9829a5f8 state=finished returned NoneType>
    如果加上pool.shutdown(),就是等任务全部结束,才会走pool.shutdown() 下面的代码,




    3,进程池
    from concurrent.futures import ProcessPoolExecutor
    pool = ProcessPoolExecutor(5) #进程池不传参数,默认当前CPU的个数
    #异步回调机制:当异步提交的任务有返回结果之后,会自动触发回调函数的执行





    4,协程:
    1,什么是协程:单线程下实现并发 只是一个名称,即表示一个效果
    进程:正在运行的程序,资源单位
    线程:cpu最小的执行单位
    并发:看起来像同时进行,就可以称之为并发,即切换+保存状态
    并行:真正的同时进行,单核情况下无法并行
    多道技术:1,空间上的复用 即 多个程序利用一台计算机
    2,时间上的复用 切换+保存状态
    切换的状态:1,程序遇到IO操作,就会进行切换
    2,长时间的占用CPU 时,时间片用完,也会切换

    程序员自己通过代码自己检测程序中的IO
    一旦遇到IO自己通过代码切换
    给操作系统的感觉是你这个线程没有任何的IO
    ps:欺骗操作系统 让它误认为你这个程序一直没有IO
    从而保证程序在运行态和就绪态来回切换
    提升代码的运行效率
    gevent模块
    import time
    from gevent import monkey;monkey.patch_all() #固定写法
    from gevent import spawn

    # 注意gevent模块没办法自动识别time.sleep()等io情况
    # 需要你手动在配置一个参数,自动检测io,遇到io就开始切换

    def heng():
    print('哼22')
    time.sleep(1)
    print('哈哈哈我')

    def ao():
    print('嗷嗷')
    time.sleep(3)
    print('收拾一下')

    start = time.time() # 在这里注意spawn()是有返回值的,返回值是一个类的对象
    g1 = spawn(heng) # spawn ,相当于一个列表,先来一个heng添加到列表中,后面再来一个ao在添加到列表中
    g2 = spawn(ao) # 一旦heng遇到IO 就执行ao,一旦ao遇到IO就立即执行heng,就是不断来回切换
    g1.join() # 等待任务完成,不然就不会执行此任务,而是走主线程,主线程没代码,程序直接结束
    g2.join() # 在右键运行后,spawn就在这两个任务之间来回疯狂的切,这个切换是在代码层面的切
    # 来欺骗操作系统,让操作系统误认为没有遇到IO
    # heng() # 串行执行
    # ao() # 串行执行 这样执行的结果是5秒多
    print(time.time()- start) # spawn(heng) spawn(ao)执行的结果
    5,IO模型
    数据交互,要的数据都在内存,是互相把数据发到对方的内存
    1,阻塞IO
    先系统要数据,没有数据时,阻塞+等待数据,一旦有数据来了
    进行数据的拷贝,拷贝到数据在回复ok,中间等待和拷贝的过程都是阻塞IO
    2, 非阻塞IO
    程序处于运行态和就绪态,向内存要数据,没有数据也会立马给你返回一个结果
    一直反复的要,一直反复的回,直到有数据真的来了,就会进行拷贝,此时会形成阻塞
    这就是非阻塞io
    3, 异步IO
    异步进行,异步提交任务后,立即给你一消息,但是内部在等待,等到内部有数据是立马
    返回给你,进行下一步操作

    4, IO多路复用
    就是 select,相当于一个检测机制,像一个列表,统一管理,要什么数据select去负责跟
    内存要数据,由他负责,不用你管,有了之后回来给你,然后再执行以下操作,相当于餐厅服务员
  • 相关阅读:
    (转)MapReduce源码分析总结
    Linux SSH远程文件/目录传输命令scp
    Hadoop学习总结:MapReduce的过程解析
    Python 3 的新特性zz
    Tutorial Learn Python in 10 minutes[zz]
    Hadoop学习总结:Hadoop的运行痕迹
    Python 绝对简明手册
    Linux命令总结
    [Error] 'strlen' was not declared in this scope
    养成C#编程好习惯
  • 原文地址:https://www.cnblogs.com/Fzhiyuan/p/11360955.html
Copyright © 2011-2022 走看看