• 进程与线程


    参考学习方法:
    1.通读博客
    2.看笔记,照着上课的代码重新敲一遍
    3.在敲代码的过程中再确认一下是不是有不了解的地方
    4.如果有不了解的 : 和周围的同学一起讨论 找周围学习好的同学问 来问老师
    5.一遍敲笔记 一遍把注释写下来
    6.把你敲得代码删掉,只留注释
    7.不要看笔记,对照注释默写代码
    操作系统的作用:
    1:隐藏丑陋的硬件端口,提供;良好的抽象接口给用户更好的体验
    2:管理,调度进程,并将对进程的竞争变得有序
    多道技术:
    针对单
    核,实现并发
    3解决多个代码在执行时,抢占资源,对多个进程的切换去运行
    1;时间上的复用:
    在同一时间完成
    a.cpu遇到io阻塞切换至其他进程
    b,cpu处理一个进程时间过长就会切换
    2:空间复用:多个进程占有内存,
    3.在任务之间的切换时根据io 阻塞来切换的.提高了效率
    进程在操作系统的三状态:
    就绪 阻塞 运行
    (1)就绪(Ready)状态
       当进程已分配到除CPU以外的所有必要的资源,只要获得处理机便可立即执行,这时的进程状态称为就绪状态。
      (2)执行/运行(Running)状态当进程已获得处理机,其程序正在处理机上执行,此时的进程状态称为执行状态。
      (3)阻塞(Blocked)状态正在执行的进程,由于等待某个事件发生而无法执行时,便放弃处理机而处于阻塞状态。引起进程阻塞的事件可有多种,例如,等待I/O完成、
    申请缓冲区不能满足、等待信件(信号)等。

    分时操作系统:
    操作系统会根据cpu使用的时间来切换,
    时间片:每个人任务分配cpu 执行的时间
    同时执行,每个进程都可以占用cpu 执行,
    能够把几个任务之间的数据隔离开,并且记录执行中的数据状态
    更好的提供了用户体验
    串行 和 并行
    # 并发 : 站在多个程序/任务的角度上看的,来回切换去执行,
    # 并行 :多个CPU,多个任务同时在CPU上执行
    # 串行 :一个CPU,代码在这个cpu上一条一条顺序执行
    # 站在CPU执行指令的角度上看的
    同步异步
    # 同步 : 执行一个任务,必须要等待这个任务有结果才返回/才进行下一个任务
    # sk.accept
    # conn.recv
    # conn.send
    # login

    # 异步 : 执行一个任务,不必等待这个任务的结果

    阻塞非阻塞 : 看cpu有没有停止对这个任务的执行
    # 阻塞 让你的程序会陷入等待的 recv recvfrom accept sleep input acquire

    # 非阻塞
    同步阻塞同步非阻塞异步阻塞异步非阻塞

    同步阻塞:
    程序必有回应,才能继续接着运行如((accept,recv 然后接收的那一端就不会做然后事情)

    同步非阻塞: 在同步运行的时候,不阻塞可以运行其它的进程

    异步非阻塞:俩者异步的,并且不阻塞,进程继续执行


    阻塞:
    阻塞调用是指调用结果返回结果之前,当前线程会被挂起的,函数只有在得到结果后才会将阻塞的线程激活
    ,而同步调的当前线程是激活的,只是逻辑上当前函数没有返回罢了
    1. 同步调用:apply一个累计1亿次的任务,该调用会一直等待,直到任务返回结果为止,但并未阻塞住(即便是被抢走cpu的执行权限,那也是处于就绪态);
    2. 阻塞调用:当socket工作在阻塞模式的时候,如果没有数据的情况下调用recv函数,则当前线程就会被挂起,直到有数据为止。


    进程与线程区别:

    多进程
    多个程序 能够 同时在操作系统中 执行
    多进程 : 开销 数据隔离
    一个程序 不太适合开启很多个进程

    并发的需求越来越大,多个CPU的出现
    一个新的单位
    线程
    线程是进程的一部分
    一个线程必须依赖进程存在
    一个进程之内至少有一条线程
    进程中默认存在的线程 主线程
    也可以在一个进程中开启多个子线程来完成更多的事情
    线程 - 轻量级(轻型)进程
    比进程的开销小很多
    进程和线程之间的关系
    线程是属于进程


    进程是计算机中最小的 资源分配单位
    线程是计算机中能被CPU调度的最小单位,计算机中最小的执行单位

    多个进程之间的多条线程可不可以利用多核
    同一个进程中的多条线程可不可以利用多核
    一个进程之间的多个线程是完全可以利用多核的
    正常的进程和线程之间的区别
    进程 : 数据隔离开销大
    线程 : 数据共享开销小






    **********进程:
    操作系统引入进程的概念的原因:
    从理论上来说,是对正在运行的程序过程的抽象
    从实现的角度 来说,是一种数据结构,目的在于清晰的刻画出动画系统的内在规律
    有效管理合和调度进入计算机系统主内存储存器运行的程序
    进程的概念:
    进程:就是计算机关于数据集合的一次活动,是系统进行资源分配基本单位,是操作系统结构的基础,
    进程是一个实体 有内存空间,包括文件区域,数据区域,文本区域执行处理机制的代码,
    堆栈区域储存着活动过程调用的指令和本地变量

    也可以说进程是:
    1.运行中的程序就是一个进程。所有的进程都是通过它的父进程来创建的。因此,运行起来的python程序也是一个进程,
    那么我们也可以在程序中再创建进程。多个进程可以实现并发效果,也就是说,当我们的程序中存在多个进程的时候,
    在某些时候,就会让程序的执行速度变快。
    2.进程是多道技术出现后,为了刻画系统内部出现的动态情况,描述系统内部各道程序活动的规律引出来的一个概练,
    所有多道程序的设计操作系统都是建立在进程的基础上.

    进程的特点:
    动态性;进程的实质就是多道程序系统中的一次执行,进程是动态产生,动态的消亡
    并发性:任何进程都可以同其他的进程一起并发执行
    独立性:由于进程是一个独立的运行的基本单位,同时也是系统分配资源和调用的独立单位
    异步性:由于进程间是互相制约的,使用进程具有执行 的时间间断性
    结构特性:进程由程序,数据和进程控制 这三块组成的
    多个不同的进程可以包含相同的程序,一个程序在不同的数据里构成不同的进程,能够得到不同的结果,
    但是执行过程中,程序不能发生改变
    程序可以作为一种软件质料长期存储,而进程是具有一定的生命期
    并行:同时多个进程进行执行 多核的系统
    并发:并发资源有限情况下,是来回切这着进行 单核的必定存在

    同步:
    一个结束了,才能进行下一个程序
    异步:给一个程序发送指令,就不用管了就自己运行自己的

    同步阻塞:
    被等待了,一值在等待着:拿函数来说,该程序一直阻塞在该函数的调用处,就不能继续往下执行
    异步阻塞:在被通知的消息被触发时,就被阻塞在这个等待操作上了

    linux:
    理论上: 各个进程的开启和结束互相不影响,不依赖.
    主进程的开启与子进程开启没有任何依赖.
    什么叫进程结束?
    代码运行完毕叫进程结束么? 你的进程空间在内存中真正的消失才算是进程结束.
    子进程是在主进程的基础上创建的,并且结束子进程的时间节点主进程必须要知道.
    僵尸进程: 死而不腐, p1 p2 p3 在代码结束时都没有完全死掉,
    他们会形成一个僵尸进程:僵尸进程只会保存pid,运行时间,状态.
    我的主进程为什么要获取僵尸进程的这些保留的数据呢?
    僵尸进程会占有一点空间,僵尸进程会占有pid进程号,
    僵尸进程的回收,是由主进程发起的.

    孤儿进程?
    你的主进程意外挂了,剩下 p1 p2 p3 就形成 孤儿进程
    所以你的孤儿都会交给'民政局'处理. init 是 Linux 所有进程的主进程.

    僵尸进程有害?有害的.
    僵尸进程他的回收取决于主进程,如果主进程产生了大量的子进程,但是不着急回收这些变成了的僵尸进程.

    孤儿进程有害? 无害 都会被民政局 init 回收.

    具体回收方法:windos 有 waitpid()
    p1.join()源码中 有waitpid()方法.

    在python程序中的进程操作
    multiprocessing 模块,分为四个模块:
    1创建进程部分Process() 2进程通信的部分 Queue()
    3进程池的部分 Pool() 4进程之间的数据共享部分 Mannage

    在Linux 与windos 系统有区别的:
    在Windows操作系统中由于没有fork(linux操作系统中创建进程的机制)
    ,在创建子进程的时候会自动 import 启动它的这个文件,而在 import 的时候又执行了整个文件。因此如果将process()
    直接写在文件中就会无限递归创建子进程报错。所以必须把创建子进程的部分使用if __name__ ==‘__main__’
    判断保护起来,import 的时候 ,就不会递归运行了。



    进程之间的通信:IPC(各种队列)
    列如进程中的队列:
    本类进程之间 的信息是独立的,互不相关,所以想要实现进程之间的通信就得,用到队列 先进先出,put get
    同样的是通过导入模块来使用
    最重要的特点就是先进先出



    进程锁:
    # 抢票的例子
    直接锁一个函数,或者一代码都可以
    那段函数,功能使用到数据了 为了 数据安全就得给它加上锁.

    with lock :
    func()
    因为本身抢票 ,就是一个多并发的,因为数据在操作的过程中是需要时间,网络上的阻塞的,不能并发,只能串行

    进程队列
    队列的特点 : 先进先出 进程之间数据安全
    就绪队列 : 由操作系统维护这任务之间谁先被运行的顺序的一个数据结构
    队列的底层 : 管道 + 锁
    # 管道Pipe 是没有锁的 数据不安全的
    # from multiprocessing import Pipe
    管道的底层 :
    socket 基于文件地址家族的通信


    进程池:Pool
    1 .为什么要有进程池 ?
    在创建进程是需要耗费时间,销毁也需要时间,也就减低了效率
    2 .多个进程能不能利用多核(多个cpu)
    能最多能利用多少个cpu?电脑有多少个cpu就能够最多同时利用多少个进程
    如果我们可以忽略IO操作,这个时候我们起超过cpu个数过多的进程个数反而会降低程序的执行效率

    进程池:
    概念:对多个任务,只创建对应的几个线程,而不是每一个任务都去创建一个线程:
    异步提交的时候,当几个任务很短暂的时候,就会被第一个进程给执行完了,所以他们的进程id是一样的
    进程池中就没有必要在去创造第二条进程了
    一般用于高级算型的
    同步提交基本不用,一个一个进程去跑的,就会起多个进程

    在进程池中获取返回值 因为进程之间数据本身就是隔离的

    Lock 是从魔块中到入的,把一段代码变为串行,把异步变为同步
    所以加锁保证数据安全
    查票可以并发但是买票就不能了 因为在并发中,cpu切换得很快 而不是
    等一个程序结束了在进行另外一个程序,在写入json 是还写好已经被读了所以就导致一张票多卖


    线程:
    为什么会有线程
    socket 网络上的服务
    我们希望我们的应用能够在同一时刻做更多的事情
    并且还能共享一段数据
    线程:
    概念:是cpu调度的单位 也是轻型的进程
    线程就是依赖于进程 , 在同一个进程中的线程共享进程中的数据

    用法: 用于实现多并发,来回切换比多进程之间的切换还要快,在io阻塞长的话时用进程?
    还是说用多进程,以为多进程是支持多核的,而多线程是不支持多核的()仅限于在python 解释器中pyCharm)

    threading
    Thread类
    线程的效率
    线程之间的数据共享
    线程不同于进程的地方 :效率 数据共享 不能在外部被结束(terminate)
    使用面向对象的方式开启线程
    守护线程
    线程的数据安全问题
    GIL锁
    互斥锁
    递归锁
    死锁现象
    queue模块
    能够保证数据在多个线程之间进行安全的数据传递
    队列

    优先级队列
    concurrent
    线程池
    进程池



    线程池 :
    这是一个公共的模块
    进程池 线程池
    都可以去用的,高度去用的

    队列锁:
    锁:
    1:Lock 锁
    2:Rlock递归锁
    3:都会造成死锁的现象,当Lock锁死锁了可以用递归锁先去解决,在考利逻辑问题,把多个变量锁一起
    从根本商 去解决问题

    队列:
    Queue 对列
    fifo 先进先出

    进程的代码:
    import os
    os.getpid()当前进程的id  os.getppid() 父进程的id 
    
    开启进程的俩种方法:
    
    第一种:
    from  multiprocessing import Process
    import os
    def func(name):
        print(f'{name}好嗨哦')
    def main():
        print(os.getpid())
    if __name__ == '__main__':
        p = Process(target=func,args=(1,))
        p.start()
    
    第二种类的方法:
    class Myclass(Process):
        def __init__(self,name):
            super().__init__()
            self.name =name
        def run(self):
            # 子进程的代码都写在这
            a = 1
            b = 2
            print('%s is runing' %self.n)
    
    if __name__ == '__main__':
        p = Myclass('ok')
        p.start()
    
    进程池的异步提交:
    apply(函数, args=(参数))
    同步调用一般不用
    import os
    from multiprocessing import Pool
    def func(i, ):
        time.sleep(0.1)
        i * i
        print(os.getpid())
    if __name__ == '__main__':
        strat = time.time()
        p = Pool()
        一: 异步提交
        for i in range(10):
            p.apply_async(func, (i,))  # apply提交任务 asyncy 异步
        p.close()  # 关闭池子
        p.join()  # z阻塞
        print(time.time() - strat)
        二:
        strat = time.time()
        p_l = []
        for i in range(20):
            p = Process(target=func, args=(1,))
            p.start()
            p_l.append(p)
        for p in p_l:
            p.join()
        print(time.time() - strat)
    进程池异步提交:
    import time
    from multiprocessing import Process, Pool
    
    
    def func(i):
        i + i
        return '*' * i
    
    
    if __name__ == '__main__':
        p = Pool()
        lis = []
        #
        a = time.time()
        ret = p.map(func, range(5))
        for i in ret:
            print(i)
        print(time.time() - a)
        二
        a = time.time()
        for i in range(5):
            ret = p.apply_async(func, (i,))
            lis.append(ret)
        for ret in lis:
            print(ret.get())
        print(time.time() - a)
    
        三
        a = time.time()
        for i in range(5):
            ret = p.apply_async(func, (i,))
            lis.append(ret)
        p.close()
        p.join()  # 执行完了一起出来
        for i in lis:
            print(i.get())
        print(time.time() - a)
    
    ** ** ** map
    import os
    from multiprocessing import Pool
    
    
    def func(i, ):
        time.sleep(0.1)
        i * i
        return "i" * i
    
    
    if __name__ == '__main__':
        p = Pool()
        re_1 = p.map(func, range(5))  # map 内置了close  与 join
        for i in re_1:
            print(re_1)
    '''
    生成者消费者模型
    import time,random
    from multiprocessing import Process,Queue
    def consumer(q,name):
        while 1:
            task = q.get()
            if not task:break
            time.sleep(0.1)
            print(f'{name}吃了{task}')
    def producer(q,n):
        for i in range(n):
            time.sleep(random.random())
            print(f'生成了{i}个')
            q.put(f'生成了{i}个')
    if __name__ == '__main__':
        q = Queue()
        lis = []
        for i in range(5):
            p = Process(target=producer,args=(q,10))#五个生产者
            p.start()
            lis.append(p)
        p1 = Process(target=consumer,args=(q,'alex'))#俩个消费者
        p2 = Process(target=consumer,args=(q,'big'))
        p1.start()
        p2.start()
        for p in lis:
            p.join()
        q.put(None)#为什么叫put(None) 而且因为有俩生产者,要是在生产者的子进程中put(None) 的话不够取 所以在就主进程中俩put(None)
        q.put(None)#应为生产的不够吃,想要结束的话就用ifp判断让消费者不在消费,多少个消费者就多少个put(None)
    # 进程中的队列,解决了,进程之间的通信,包括子进程与父进程的通信
    
    #基于socket 用多进程解决并发聊天
    
    # server 端
    import socket
    from multiprocessing import Process
    server = socket.socket()
    server.setsockopt(socket.SOL_SOCKET,socket.SOCK_STREAM,1)
    server.bind(('127.0.0.1',8888))
    server.listen(5)
    def talk(conn,client_addr):
        while 1:
            try:
                mag = conn.recv(1024)
                if not mag:break
                conn.send(b'adfs')
            except Exception:
                break
    if __name__ == '__main__':
        while 1:
            conn,addr = server.accept()
            p = Process(target=talk,args=(conn,addr))
            p.start()
    
    # 客户端client
    client =socket.socket()
    client.connect(('127.0.0.1',8888))
    while 1:
        client.send(b'sdfsa')
        msg = client.recv(1024)
        print(msg)
    
    #******** 线程的代码
    '''下面代码为了证明:子线程与父线程的数据共享的
    from threading import Thread
    n =10
    def fucn():
        global n
        n -=1#----->子线程n 的变化
    lis = []
    for i in range(10):
        t = Thread(target=fucn)#开启十个线程
        t.start()
        lis.append(t)
        print(n)
    for i in lis:
        i.join()
    print(n)  #-----主线程n
    '''
    
    
    # 主线程会等待子线程结束后才结束
    #查看线程名
    import time
    from threading import Thread
    def func():
        time.sleep(1)
        print(' in func')
    
    t = Thread(target=func)
    t.start()
    print(t.ident)#线程地址
    print(t.name)#线程名称
    
    类方式 查看线程名
    import time
    class MyThread(Thread):
        def __init__(self,i):
            super().__init__()
        def run(self):
            time.sleep(1)
            print('in mythread',self.name,self.ident)
    for i in range(5):
        t = MyThread(i) #需要传参的话就需要,__init__
        t.start()
    
    import time
    from threading import currentThread,active_count,enumerate,Thread
    def func():
        time.sleep(1)
        #导入currentThread直接使用,直接在函数中点  得到线程名,线程地址
        print('in func',currentThread().name,currentThread().ident)
    t = Thread(target=func)
    t.start()
    print(t.ident)#线程名
    print(t.name)#线程地址
    
    def foo():
        time.sleep(1)
        print(' in func',currentThread().name,currentThread().ident)
    t =Thread(target=func)
    print(enumerate())    # 当前所有活着的线程对象组成的列表
    print(active_count()) # 统计当前所有活着的线程对象的个数 len(enumerate)
    print(t.ident)  # 线程id
    print(t.name)   # 线程名
    
    线程的守护进程
    import time
    from threading import Thread
    def func():
        while 1:
            time.sleep(1)
            print('in func')
    def son():
        print('son start ')
        time.sleep(1)
    t = Thread(target=func)
    t.setDaemon(True)
    t.start()
    Thread(target=son,).start()
    time.sleep(4)
    线程是否存在数据安全问题
        数据共享
    GIL锁 :能够保证在同一时刻 不可能有两个线程 同时执行    CPU指令
    为什么有了GIL还需要手动加锁
    为什么append这样的方法和+=这样的方法在数据安全性问题上是不一样
        由于append是一个完整的指令过程,执行了就相当于添加,不执行就还没添加
        += 先执行+法,再对结果进行赋值
    
    线程的数据安全:
    from threading import Lock
    import dis
    l = []
    def func():
        l.append(1)
    a= 0
    def func2():
        global a
        with lock:
            a +=1
    lock =Lock()
    dis.dis(func2())
    print(a)
    
    
    from threading import Thread,Lock
    import os,time
    def work():
        global n
        with lock:
            temp = n
            time.sleep(0.1)
            n = temp - 1
            n = temp - 1
    if __name__ == '__main__':
        n =10
        l =[]
        for i in range(5):
            p = Thread(target=work,args=(lock,))
            l.append(p)
            p.start()
        for p in l :
            p.join()
        print(n)
    
    #科学家吃面的问题
    import time
    from threading import Lock,Thread
    noodle_lock = Lock()
    fork_lock = Lock()
    fork = 10
    noodle = 20
    def eat1(name):
        noodle_lock.acquire()
        print('%s拿到面了'%name)
        fork_lock.acquire()
        print('%s拿到叉子了' % name)
        noodel =fork + noodle
        time.sleep(0.1)
        print('%s吃到面了'%name)
        fork_lock.release()
        print('%s放下叉子了' % name)
        noodle_lock.release()
        print('%s放下到面了'%name)
    
    def eat2(name):
        fork_lock.acquire()
        print('%s拿到叉子了' % name)
        noodle_lock.acquire()
        print('%s拿到面了'%name)
        noodel =fork + noodle
        time.sleep(0.1)
        print('%s吃到面了'%name)
        noodle_lock.release()
        print('%s放下到面了' % name)
        fork_lock.release()
        print('%s放下叉子了' % name)
    
    # for i in ['yuan','alex','wusir','太亮']:
    Thread(target=eat1,args=('yuan',)).start()
    Thread(target=eat2,args=('alex',)).start()
    Thread(target=eat1,args=('wusir',)).start()
    Thread(target=eat2,args=('太亮',)).start()
    
    
    # 递归锁
    # 使用递归锁可以快速的解决死锁问题
    import time
    from threading import RLock,Thread
    fork_lock = noodle_lock = RLock()
    fork = 10
    noodle = 20
    def eat1(name):
        noodle_lock.acquire()
        print('%s拿到面了'%name)
        fork_lock.acquire()
        print('%s拿到叉子了' % name)
        noodel =fork + noodle
        time.sleep(0.1)
        print('%s吃到面了'%name)
        fork_lock.release()
        print('%s放下叉子了' % name)
        noodle_lock.release()
        print('%s放下到面了'%name)
    
    def eat2(name):
        fork_lock.acquire()
        print('%s拿到叉子了' % name)
        noodle_lock.acquire()
        print('%s拿到面了'%name)
        noodel =fork + noodle
        time.sleep(0.1)
        print('%s吃到面了'%name)
        noodle_lock.release()
        print('%s放下到面了' % name)
        fork_lock.release()
        print('%s放下叉子了' % name)
    
    # for i in ['yuan','alex','wusir','太亮']:
    Thread(target=eat1,args=('yuan',)).start()
    Thread(target=eat2,args=('alex',)).start()
    Thread(target=eat1,args=('wusir',)).start()
    Thread(target=eat2,args=('太亮',)).start()
    
    
    # 用互斥锁 来解决问题
    # 两个资源作为一个资源锁起来
    import time
    from threading import Lock,Thread
    lock = Lock()
    fork = 10
    noodle = 20
    def eat1(name):
        lock.acquire()
        print('%s拿到面了'%name)
        print('%s拿到叉子了' % name)
        noodel =fork + noodle
        time.sleep(0.1)
        print('%s吃到面了'%name)
        print('%s放下叉子了' % name)
        print('%s放下到面了'%name)
        lock.release()
    
    def eat2(name):
        lock.acquire()
        print('%s拿到叉子了' % name)
        print('%s拿到面了'%name)
        noodel =fork + noodle
        time.sleep(0.1)
        print('%s吃到面了'%name)
        print('%s放下到面了' % name)
        print('%s放下叉子了' % name)
        lock.release()
    
    # for i in ['yuan','alex','wusir','太亮']:
    Thread(target=eat1,args=('yuan',)).start()
    Thread(target=eat2,args=('alex',)).start()
    Thread(target=eat1,args=('wusir',)).start()
    Thread(target=eat2,args=('太亮',)).start()
    
    
    
    1.死锁现象
        由于多个锁对多个变量管理不当 产生的一种现象
    2.Lock 互斥锁
        在一个线程内只能被acquire一次
    3.RLock 递归锁
        在一个线程内可以被acquire多次,必须acquire多少次,release多少次
    
    
    
    
    
    # 队列:
    # import queue
    # 
    fifo 先进先出
    q = queue.Queue()
    q.get()
    q.get_nowait()
    q.put()
    q.put_nowait()
    
    lifoqueue
    后进先出的队列 = 栈  --> 算法
    lifoq = queue.LifoQueue()
    lifoq.put(1)
    lifoq.put(3)
    lifoq.put(2)
    lifoq.put(0)
    print(lifoq.get())
    print(lifoq.get())
    
    优先级队列
    pq = queue.PriorityQueue()#优先级
    pq.put((2,'wusir'))
    pq.put((1,'yuan'))
    pq.put((1,'alex'))
    pq.put((3,'太亮'))
    print(pq.get())
    print(pq.get())
    print(pq.get())
    在put()中按第一个数字的大小出来的, 出现了俩个大小一样的,元组里边的第二元素的ascll码来排  最小的先出去
    可以用去写QQ会员这样的软件
    
    
    
    线程池代码
    import  time
    from  concurrent.futures import ThreadPoolExecutor as Executor ,ProcessPoolExecutor
    -------------------------------->ThreadPoolExecutor as Executor() 或者ProcessPoolExecutor as Executor() 这样就可以无缝去使用
    def func(i):
        time.sleep(1)
        print('in son thread',i)
    #$****(1)
    if __name__ == '__main__':
        tp = Executor()  #  线程池
        tp.map(func,range(8))   #map 函数特别注意的是,参数位置,函数的位置不是关键字参数 传参的是可迭代对象
        print('所有的任务都快执行完成了')
    #******(2)   俩种的效果是一样的
    if __name__ == '__main__':
        tp =Executor()
        for i in range(5):
            tp.submit(func,i)#这个位置直接传参  #相当于 异步提交
        tp.shutdown() #写话主线程就会等待子线程完成以后在执行主线程  相当于close 和 join
        print('这里跑的是主线程')
    
    
    #如何获取返回值的
    import  time,os
    from  concurrent.futures import ThreadPoolExecutor as Executor ,ProcessPoolExecutor
    from threading import currentThread
    def func(i):
        i + i
        time.sleep(1)
        print(os.getpid(),os.getppid())
        return '^'*i
    if __name__ == '__main__':
        p = Executor(4)
    
        第一种使用使用map提交任务 获取返回值
        ret = p.map(func,range(3))#ret generator object 生成对象
        for i in ret:
            print(i)
        print('这是主线程---->',os.getpid(),os.getppid())
    
        第二种使用submit提交任务,获取返回值
        l =[]
        for i in  range(5):
            ret = p.submit(func,i)
            l.append(ret)
        for i in l:
            print(i.result())
    
    
    def func(i):
        i + i
        time.sleep(1)
        print(currentThread().name,currentThread().ident)
    if __name__ == '__main__':
        p = Executor()
        p.map(func,range(6))
        print('这是主线程------>',currentThread().name,currentThread().ident)
    
    # 
    # 
    #回调函数:
    import  time,os,random,requests
    from  concurrent.futures import ThreadPoolExecutor as Executor ,ProcessPoolExecutor
    from threading import currentThread,Thread
    def back(ret):
        print(ret.result())
    
    def son_func(i):
        time.sleep(random.random())
        return i**i
    p = Executor()
    for i in range(5):
        ret =p.submit(son_func,i)#得到函数son_func返回值
        ret.add_done_callback(back)#返回值传个back
    
    def get(url):
        obj = requests.get(url)
        if requests.status_codes == 200:
            return {'url':url,'text':obj.text}
    def parse_page(res):
        res = res.result()
        parse_res = 'url:<%s> size:[%s]
    ' % (res['url'], len(res['text']))
        with open('db.txt','a') as f :
            f.write(parse_res)
    if __name__ == '__main__':
        urls =[
            'https://www.baidu.com',
            'https://www.python.org',
        ]
        p = Executor()
        for url in urls:
            p.submit(get).add_done_callback(parse_page)
    
    
    #二分法查找
    # lis =[1,2,13,14,25,61,73,85,97,123,345,678,1234,5678,6789]
    
    #第一种纯逻辑算法:
    n =345
    lift = 0
    right  = len(lis) - 1
    count = 0
    while lift<=right:
        middle = (lift + right) // 2
        if n > lis[middle]:
            lift = middle +1
        elif n < lis[middle] :
            right = middle - 1
        else:
            print(count)
            print(middle)
            break
        count +=1
    else:
        print('不存在')
    #
    #第二种:
    lis =[1,2,13,14,25,61,73,85,97,123,345,678,1234,5678,6789]
    def func(left,right,n):
        middle = (left + right) // 2
        if left>right:     #----->边界问题 当数不存在的时候就找不到,left 与right 下标都变互逆了
            print('没找到')
            return -1
        if n > lis[middle]:
            left = middle + 1
        elif n < lis[middle]:
            right = middle -1
        else:
            return middle
        return func(left,right,n)
    p = func(0,len(lis) - 1,1)
    print(p)
    
    # 第三种:改变列表
    lis =[1,2]
    left = 0
    right = len(lis) - 1
    middle = (left + right) // 2
    lis=lis[:middle-1]
    print(lis)
    
    lis =[1,2,13,14,25,61,73,85,97,123,345,678,1234,5678,6789]
    def func(lis,n):
        left = 0
        right = len(lis) - 1
        middle = (left + right) // 2
        if right <=0:  #这个位置很关键
            print('没有找到')
            return -1
        if n < lis[middle]:
            lis=lis[:middle-1]  #边界问题
        elif n > lis[middle]:
            lis  = lis[middle+1:]#中间位置
        else:
            print('找到了')
            return lis
        func(lis,n)
    func(lis,1234)
    
    dic = {'怎么':'对方是否','1':123,'78':213}
    
    
    
    print(dic.keys())#dict_keys(['怎么', '1', '78'])  这个列表是高仿列表是不能够去 操作的
    
    print(dic.items())#dict_items([('怎么', '对方是否'), ('1', 123), ('78', 213)])#同样的这个列表且套元组的是不能够去使用的
    
    #三级菜单:
    
    dic = {'北京':{'朝阳':{'朝阳大妈':'朝阳纪委','朝阳群众':'描线'},'海淀':{'海淀区':'海胆'},'昌平':{'沙河':'黄河','黄山':'一'}},
           '上海':{'上海滩':{'发哥':'赌神'},'歌剧院':{'歌星':'不知道'}}}
    递归方法
    def treeLM(dic):
        while 1:
            for i in dic:print(i)
            key = input('请输入你选择的地址:').strip()
            if key == 'b' or key == 'q':return key
            elif key in dic.keys() and dic[key]:
                ret =treeLM(dic[key])
                if ret == 'q':return 'q'
            elif (not dic.get(key)) or (not dic[key]):
                continue
            else:
                print('好好输入')
    treeLM(dic)
    
    l =[dic]
    while l:
        for i in l[-1]:print(i)
        k = input('>>>:').strip()
        if k in l[-1].keys() and l[-1][k]:l.append(l[-1])
        elif k == 'b':l.pop()
        elif k == 'q':break
        else:continue

    lifo 先进后出 栈 用于递归的 的算法上 三级菜单

    数据的安全:
    对于list dic 这样的数据 通过增删改查 这样的操作 是不会发生数据不安全的,
    而 -= += *= 这样的挥发生数据安全问题的, 因为在算当中 会开回切换, 对于GIL锁来说
    只有一个进程把锁还回来 另外一个程序在可以被cpu运行调度 所以没有其他锁的情况下就会数据不安全


    注意:主线程会等待子线程结束之后才结束

    守护线程 :(代码t = Thread(target=func)
    t.setDaemon(True) ---设置当前线程为守护线程
    守护进程:守护进程会等待主进程的代码结束而结束
    守护线程 :守护线程会等待主线程的结束而结束
    如果主线程还开启了其他子线程,那么守护线程会守护到最后
    主进程必须后结束,回收子进程的资源
    线程是属于进程的,主线程如果结束了,那么整个进程就结束了
      
       当只有主线程 与一条守护线程 的时候 主线程 直接运行结束,不用等守护线程,运行 ,因为守护线程本身就是为了守护主线程而产生的,主线程安全运行,那么守护线程的
      的使命也就是随着结束了.


    过程
    主线程结束依赖两个事儿 (自己的代码执行完毕,非守护的子线程执行完毕)
    -->主线程结束,进程也结束了
    -->这个进程中的所有线程都结束了,所有的守护线程也就不存在了


    锁:
    在python中的线程 是不能利用多个CPU -- 全局解释器锁 GIL
    import dis # 内置模块 能够查看python代码翻译成的机器语言

    GIL锁:
    GIL锁 :能够保证在同一时刻 不可能有两个线程 同时执行 CPU指令
    面试题:
    有了这个锁 多线程是不是就没用了?
    socket recv accept 在高IO操作的时候多线程仍然比多进程好用很多很多
    GIL全局解释器锁 是 Cpython解释器中的
    Jpython pypy 都支持多线程访问多核
    为什么这个锁要加上啊? 历史遗留问题 + python是解释型语言的现实情况
    为什么不把这个锁去掉啊? 尝试着去掉过 效果不好
    多线程不能利用多核这件事情如何弥补,如何看待?
    1.不能利用多核 并不能说明在解决高IO操作的程序中python是有问题的

    2.如果我要解决的是高计算的场景呢?
    1.多进程 2.搭建集群和分布式系统



  • 相关阅读:
    高德车载导航自研图片格式的探索和实践
    导航定位向高精定位的演进与实践
    高德算法工程一体化实践和思考
    机器学习在高德用户反馈信息处理中的实践
    UI自动化技术在高德的实践
    高德网络定位算法的演进
    系统重构的道与术
    基于深度学习的图像分割在高德的实践
    MySQL索引那些事
    如何优雅的将Mybatis日志中的Preparing与Parameters转换为可执行SQL
  • 原文地址:https://www.cnblogs.com/LMTlmt/p/10472287.html
Copyright © 2020-2023  润新知