• python之路--线程的其他方法


    一 . current_thread的用法

    import threading
    import time
    from threading import Thread, current_thread
    def func(n):
        time.sleep(1)
        print('子线程名称', current_thread().getName())  # Thread-1
        print(f'{n}号线程任务')
    if __name__ == '__main__':
        t = Thread(target=func, args=(1,))
        t.start()
        print('主线程名称',current_thread().getName())  # MainThread
        print('主线程ID',current_thread().ident)
        print(current_thread())  # 当前运行的进程
        print(threading.enumerate())  # 列举正在运行的线程
        print(threading.active_count())  # 查看有多少正在运行的线程

    二 . 线程队列(重点)

      1. 先进先出(FIFO)队列 (常用)

    import queue
    # 一:先进先出队列
    q = queue.Queue(3)  #先进先出 fifo first in first out
    q.put(1)
    q.put(2)
    print('当前队列内容长度',q.qsize())
    q.put(3)
    print('查看队列是否满了', q.full())
    try: 
        q.put_nowait(4)  # 用put_nowait 因为队列是共享的,不确定谁往里面放东西,所以用它试错
    except Exception:
        print('队列满了')
    print(q.get())
    print(q.get())
    print('查看队列是否为空', q.empty())
    print(q.get())
    print('查看队列是否为空', q.empty())
    try:
        q.get_nowait()  # queue.Empty
    except Exception:
        print('队列空了')

      2.先进后出(FILO) (常用)

    import queue
    # 二 先进后出队列,或者后进先出,类似于栈
    q = queue.LifoQueue(3)
    
    q.put('乔峰')
    q.put('段誉')
    q.put('虚竹')
    
    print(q.get())  # 虚竹
    print(q.get())  # 段誉
    print(q.get())  # 乔峰

      3.优先级队列 (不常用)

    import queue
    #优先级队列
    q = queue.PriorityQueue(5)
    # 先比较元组前边数字的大小,数字越小优先级越高, -1 < 0 < 1,
    # 如果数字相同,比较元元组第二项
    q.put((5,'alex'))
    q.put((2,'宝宝'))
    q.put((7,'大力'))
    
    print(q.get())  # (2, '宝宝')
    print(q.get())  # (5, 'alex')
    print(q.get())  # (7, '大力')

    三 . 线程池(重点)

    import time
    from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor
    def f1(n,s):
        time.sleep(1)
        # print(n,s)
        return f'{n}号' + s
    
    if __name__ == '__main__':
        tp = ThreadPoolExecutor(4)  # 线程的个数里面的参数 * 5, 不写参数就是cpu核数 * 5
        # tp = ProcessPoolExecutor(4) 这个是进程,这个方法比较常用 进程的个数就是参数,不写就是cpu 的核数
        # tp.map(f1,range(10))  #异步提交任务(瞬间提交,不执行里面的函数),参数同样是任务名称,可迭代对象
        res_list = []
        for i in range(10):
            # tp.submit(f1,{'段誉':i},'六脉神剑')  不能接返回值,下面的可以
            res = tp.submit(f1,i,'乔峰')  # submit是给线程池异步提交任务, 里面随便传参
            print(res)
            res_list.append(res)
        tp.shutdown()  #主线程等待所有提交给线程池的任务,全部执行完毕 close + join
        for r in res_list:
            print(r.result()) # 相当于 进程里面的 .get()
        print('主线程结束')

    四. 协程

       1. 生成器版协程(最low,了解)

    import time
    def f1():
        for i in range(5):
            time.sleep(0.5)
            print('f1>>',i)
            yield
    def f2():
        g = f1()
        for i in range(5):
            time.sleep(0.5)
            print('f2>>', i)
            next(g)  
    f1()
    f2()
    # f2 与 f1 交替出值

      2. greenlet版协程(中档,了解)

    import time
    from greenlet import greenlet
    def f1(n):
        print('第一次执行f1' + n)
        time.sleep(1)
        g2.switch('阿朱')  # 第一次传参就行 以后的g2.switch() 不用传参
        print('第二次执行f1' + n)
        g2.switch()
    def f2(n):
        print('第一次执行f2' + n)
        time.sleep(1)
        g1.switch()
        print('第二次执行f2' + n)
    g1 = greenlet(f1)  # 实例化一个greenlet对象,并将任务名称作为参数参进去
    g2 = greenlet(f2)
    g1.switch('乔峰') # 里面可以传参, 执行g1里面的任务

      3. gevent 真正的协程(重点)

    from gevent import monkey;monkey.patch_all()
    import gevent
    import time
    def f1():
        print('第一次f1')
        # gevent.sleep(1)
        time.sleep(2)
        print('第二次f1')
        return 15
    def f2():
        print('第一次f2')
        # gevent.sleep(2)
        time.sleep(3)
        print('第二次f2')
    s = time.time()
    g1 = gevent.spawn(f1)  # 异步提交了f1任务
    g2 = gevent.spawn(f2)  # 异步提交了f2任务
    gevent.joinall([g1,g2]) # 必须joinall 不然主协程代码执行结束后就结束,不管上面的代码是否执行
    e = time.time()
    print('执行时间:', e-s)
    print('主程序任务')
    # 两个gevent模块必须都导入,如果只import gevent模块,那么只有gevent.sleep()这种IO模式可以并发,其他IO不支持并发

      上例gevent.sleep(2)模拟的是gevent可以识别的 IO阻塞. 而time.sleep(2)或者是其他的阻塞, gevent是不能直接识别的, 需要用下面的一段代码, 打补丁, 就可以识别了. from gevent import monkey;monkey.patch_all, 这段代码必须放在被打补丁者的前面,如time, socket模块之前. (只要用到gevent 就直接写在最前面把)

    五 . 线程池回调函数

    from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor
    def f1(n,s):
        return n+s
    def f2(n):
        print('回调函数>>>', n.result())   # 回调函数>>> 23
    if __name__ == '__main__':
        tp = ThreadPoolExecutor(4)
        res = tp.submit(f1, 11, 12).add_done_callback(f2)

      

  • 相关阅读:
    自顶向下的单元测试策略
    孤立的测试策略
    单元测试
    控制流与数据流,信息流
    白盒测试的特点
    白盒测试
    黑盒测试优缺点
    appium对博客园APP进行自动化测试
    招聘测试人员,我在面试什么?
    测试开发这一年
  • 原文地址:https://www.cnblogs.com/attila/p/10267987.html
Copyright © 2020-2023  润新知