zoukankan      html  css  js  c++  java
  • 网络编程的小结

    计算机操作系统发展史

    1.多道技术

        1.空间复用

            同一时间在内存中存放多个程序  内存相互隔离

        2.时间复用

            CPU在遇到IO时切换到另一个程序

        可以实现并发

            切换+保存状态

    2.进程 理论 *****

        进程是一个资源单位  包含了该程序运行所需的所有资源

        为什么使用它? 为了提高程序的执行效率   当遇到IO阻塞时  或需要同时执行多个任务时

        linux 和 windows创建进程的区别

        linux下创建进程 会直接将父进程的所以数据复制一份给子进程

        windows创建进程时 子进程会加载父进程的字节码(没有任何的多余符号)

    3.进程 的使用

        1.实例化Process这个类  传入一个target参数

        2.继承Process  实现run函数

    4.IPC

        为什么使用IPC? 进程间的内存是物理隔离的  无法直接访问数据

        实现方式

        1.共享文件    速度慢 没有锁

        2.管道        单向通讯  需要有父子关系  没有锁

        3.共享内存    速度快  数据量较小  Manager没有锁    Queue有锁(先进先出)

    5.守护进程

        A进程守护B进程    B 进程结束 A也结束  (皇帝死了 妃子陪葬)

    6.互斥锁  死锁 可重入锁  信号量   (抢票代码  死锁代码)

        1.互斥锁

            问题?  多个进程同时读写同一份数据时 可能造成数据混乱  (本地IO速度很快 基本不会出现问题)

            读数据没有必要加锁

            写数据必须加

            锁的特点:

                并发改串行

                被锁的代码将会变成串行 效率降低

            锁的原理

                就是加上一堆判断 锁相当于一个标记

            互斥锁 相互排斥  

            同一线程不能多次acquire   会卡死

        2.死锁?

            死锁造成的问题.程序卡死

            一个锁不会产生死锁

            当有多个锁多个线程时会产生死锁

            a b  锁

            p k  线程

            当p 和 k 都需要a和b锁时才可能产生死锁

        3.可重入锁RLock

            同一个线程可以多次执行acquire  执行一次acquire  计数加1

            执行一次release 次数减一 执行acquire的次数需要与release的次数对应

            在执行被锁的代码时   同一个线程 不会判断次数   其他线程需要判断 计数为0才可以执行

            不是用来解决死锁的

        4.信号量

            案列:

            sem = semaphore(2)

            acquire

            code.....

            release

            开了十个线程 只能有两个同时执行

            信号量作用:限制同时执行被锁代码的线程数量

    7.生产者消费者模型

        while Trur:

            生产数据  1

            处理数据  10

        生产数据 和 处理数的能力不匹配  一个快一个慢  整体下变低

        学习多进程 可以将生产和处理 分到不同进程中  来解决能力不匹配的问题 快的多干点 慢的少干点

        第二个问题  作为处理数据的一方不知到什么时候会有数据 两个进度不同  使用一个共享的数据容器

        将生产和消费分到不同进程(线程)中 使用共享数据容器来同步数据

    8.线程理论 *****

        线程是CPU的基本执行单位

        一连串的代码就是流水线

        cpu会按照顺序依次执行他们

        为什么用?  需要实现并发执行任务  并发任务进程也可以完成

        线程和进程的区别

            1.资源开销

                进程开销大  线程开销小

            2.数据共享

                一个进程内的所有线程数据共享

            举例:

            一个进程中 必然包含一条主线程

            一个进程可以包含多个线程

            进程是工厂 线程 是流水线

            一个工厂有多个流水线 至少得有一个 所有流水线都可以使用工厂内的资源

    9.线程的使用  (生产者消费者代码   抢票代码)

         使用线程

            1.实例化Thread类 参数target传入任务

            2.继承Thread类 实现run函数

    10.守护线程

        守护线程 会在被守护线程结束时一并结束

        与守护进程的区别

        a 守护 b  同时还有另一个线程 c

        a 会等到 b 和 c都结束才结束

        守护线程会等待所有非守护线程结束后才算结束

         main

         sub1

         sub2

         sub3

         sub1.deamon = True

         sub1会等待 main sub2 sub3 全都结束 才会结束

    11.GIL

        问题: 一个py程序 要想运行 必须运行解释器 解释器的工作时翻译代码 并执行

               当一个py进程中 有多个线程 线程的任务就是执行代码  意味者 多个线程都要使用解释器

               简单的说 多线程会争抢解释器的执行权

               如果是自己开的线程  多线程要访问相同数据 加锁就能解决

               但是有一写代码不程序员写的 也确实需要共享使用 就是解释器

        GC:垃圾回收器  负责清理内存中的无用数据 清理垃圾也需要执行代码  但是GC不应该卡住用户的代码执行

            只能开线程

            GC 看到 x = 10   x = 1   准备删除10  这时候突然CPU切到用户线程  a = 10  此此时还没有问题

            紧接着 CPU 又切到GC  GC上来就删除10  在切到用户线程 a 所指向的地址被清理了 产生错误

        解决方案: 给解释器加上锁  保证GC执行期间 用户线程不能执行

        全局解释器锁带来的问题

            同一时间只有一个线程能使用解释器  无法利用多核CPU

            那Cpython 多线程是鸡肋?

            当程序是IO密集时 多线程能提高效率   IO的速度 明显要比CPU执行速度慢

            当程序时计算密集时  多线程无法提升效率  得使用多进程

    12.GIL 和 自定义锁

        相同点:都是互斥锁

        不同点:

             GIL解释器级别锁 锁的时解释器代码

             自定义锁 锁的是自己写的代码

             自动加锁只要有线程在使用解释器     自动解锁 1.IO  2.执行时间过长3ms 3.线程执行结束

        有了GIL 为什么还需要自定义锁?

            GIL 不清楚什么代码会造成数据竞争问题  不知道什么地方该加

    13.进程池,线程池

        池是一种容器

        进程池里面装的是进程

        为什么需要这个容器?

            当程序中有多个进程时 管理变得非常麻烦

            进程池可以帮我们管理进程

                1.进程的创建

                2.进程的销毁

                3.任务的分配

                4.限制最大的进程数 保证系统正常运行

        使用方式?

            ThreadPoolExecutor  线程池

                实例化 时指定最大线程数

            ProcessPoolExecutor  进程池

                实例化 时指定最大进程数

            执行submit来提交任务

    14.队列   queue 这个queue和进程里的Queue不同 就是一个简单的容器

        队列是一种数据的容器

        特点:先进先出

        queue先进先出

        lifoqueue先进先出

        priorityqueue  优先级队列  整型表示优先级   数字越大优先级越低

    15.同步异步 阻塞 非阻塞   概念

        同步

            提交任务需要等待任务执行完成才能继续执行

        异步

            提交任务不需要等待任务执行 可以立即继续执行

        指的是提交任务的方式

        阻塞

            阻塞

            遇到IO  失去了CPU执行权  看上去也是在等 与同步会混淆

        非阻塞

            就绪  运行

            代码正常执行

        阻塞非阻塞指的是线程状态

        线程的三种状态  就绪  运行  阻塞

    16.异步回调

        发起了一个异步任务 任务完成后回来调用指定的函数

        pool = ThreadPoolExecutor()

        f = pool.submit(task)

        f.add_done_callback(函数名)

    17.协程 ****

        协程 指的是 单线程实现并发

        为什么用协程?  多线程实现并发 有什么问题?

        TCP程序中 处理客户端的连接 需要子线程  但是子线程依然会阻塞   一旦阻塞 CPU切走 但是无法保证是否切到当前程序

        提高效率的解决方案 是想办法尽可能多的占用CPU  当程序遇到阻塞时 切换到别的任务 注意使用程序内切换

        协程的使用

            1.生成器

            2.greenlet 封装了生成器 不能检测到IO行为

            3.gevent 封装了grennlet  既能够切换执行 也能检测IO

              gevent 需要配合monkey补丁  monkey补丁内部将原本阻塞的模块 替换为了非阻塞的

              monkey必须放在导入(需要检测IO的模块)模块之前

              monkey.patch_all()

              gevent核心函数spawn(函数名)

              join让主线程等待所有任务执行完成才结束

    18.IO模型

        网络传输的两个阶段

            waitdata(recv accept)  copydata(send)

            一个应用程序的缓存 和系统缓存

            recv accept 先 wait   在copy

            send 只有copy

        阻塞IO

            之前所学 除了协程 都是阻塞 IO

            应用程序  发送 系统调用   操作系统等待数据(wait)  数据准备好 return data

        非阻塞IO

            recv send accept 都不会阻塞 会立即执行  但是不能保证立马就有数据 没有数据抛出异常

            我们需要手动捕获异常  捕获异常后可以处理别的任务

            CPU的利用率提高了

            但是同时也浪费了CPU  当没有任何数据处理的时候  就在空转

            while True:

                pass

        多路复用

            管理连接的一种方式

            为什么使用它? 相对于非阻塞IO降低无用的系统调用

            怎么管?

                核心函数select  默认时阻塞的  阻塞到有任意一个连接可以被处理

                一  创建连接 和管理连接

                1.创建服务器socket对象

                2.将服务器对象交给select来管理

                3.一旦有客户端发起连接 select将不在阻塞

                4.select将返回一个可读的socket对象列表(第一次只有服务器)

                5.服务器的可读代表有连接请求 需要执行accept  返回一个客户端连接conn  由于是非阻塞 不能立即去recv

                6.把客户端socket对象也交给select来管理  将conn加入两个被检测的列表中

                7.下一次检测到可读的socket 可能是服务器 也可能客户端 所以加上判断  服务器就accept 客户端就recv

                8.如果检测到有可写(可以send就是系统缓存可用)的socket对象 则说明可以向客户端发送数据了

                7 和 8 执行顺序不是固定的

        异步IO

            IO包括  网络IO 本地IO

            上面的三种描述的都是网络IO

            不能本地IO的问题

            解决的方案就是:

                将同步的IO操作改成异步的IO操作  在IO期间 可以执行其他的任务

            使用asyncio模块

    19.socketserver

        是什么? 对服务器端的socket的封装

                封装了多线程和socket

        为什么用? 简化代码

        使用方法:

            socketserver  (forkingUDP forkingTCP windows无法使用)

            核心类 ThreadingUDPServer ThreadingTCPServer

            ThreadingTCPServer 实例化时  传入服务器地址 和  自定义的一个数据处理类

            自定义类需要继承BaseRequestHandler类中需包含handle函数

            对象调用serve_forever

    20.Event

        是什么?

            线程间通讯的方式

        为什么用?

            简化代码

        set()设置为True

        wait()阻塞 直到为True

  • 相关阅读:
    Log4Net详解(2)结构篇
    vs2012中使用Spring.NET报错:Spring.Context.Support.ContextRegistry 的类型初始值设定项引发异常
    vs2010无法打开项目文件的解决方法
    Spring.NET使用assembly方式设置配置文件
    WebService生成XML文档时出错。不应是类型XXXX。使用XmlInclude或SoapInclude属性静态指定非已知的类型。
    [转贴]如何做好一个垂直搜索引擎
    怎样预防RSI呢?
    推荐一个打折的站点
    五子棋程序
    共享两本C++的好书
  • 原文地址:https://www.cnblogs.com/zhouhai007/p/9971280.html
Copyright © 2011-2022 走看看