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)

 

  

posted @ 2019-01-14 17:22  一个很善良的抱爱  阅读(178)  评论(0编辑  收藏  举报