zoukankan      html  css  js  c++  java
  • 进程与线程

    参考学习方法:
    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.搭建集群和分布式系统



  • 相关阅读:
    4.计算机启动过程的简单介绍 计算机启动流程 计算机BIOS作用 POST 开机自检 计算机启动顺序 分区表 操作系统启动
    3.操作系统简单介绍 操作系统发展历史 批处理分时系统 操作系统是什么 操作系统对文件的抽象 进程 虚拟内存是什么 操作系统作用 操作系统功能
    2.计算机组成-数字逻辑电路 门电路与半加器 异或运算半加器 全加器组成 全加器结构 反馈电路 振荡器 存储 D T 触发器 循环移位 计数器 寄存器 传输门电路 译码器 晶体管 sram rom 微处理 计算机
    1.计算机发展阶段 计算机发展历史 机械式计算机 机电式计算机 电子计算机 逻辑电路与计算机 二极管 电子管 晶体管 硅 门电路 计算机 电磁学计算机二进制
    如何解决svn清理失败 不能更新 cleanup失败 cleanup乱码 更新乱码 svn更新提示清理 清理乱码不能清理 svn故障修复SVN cleanup 陷入死循环 svn cleanup时遇到错误怎么办
    eclipse svn插件卸载 重新安装 Subclipse卸载安装 The project was not built since its build path is incomplete This client is too old to work with the working copy at
    java for循环里面执行sql语句操作,有效结果只有一次,只执行了一次sql mybatis 循环执行update生效一次 实际只执行一次
    windows资源管理器多标签打开 windows文件夹多标签浏览 浏览器tab页面一样浏览文件夹 clover win8 win10 报错 无响应问题怎么解决 clover卡死 clover怎么换皮肤
    批处理启动vm虚拟机服务 vm12启动无界面启动vm虚拟机系统 windows上如何操作服务 sc net启动关闭服务
    不能ssh连接ubuntu linux 服务器 secureCRT不能ssh连接服务器 不能远程ssh连接虚拟机的ubuntu linux
  • 原文地址:https://www.cnblogs.com/LMTlmt/p/10472287.html
Copyright © 2011-2022 走看看