getName()--ident--enumerate--activeCount--线程池--协程(gevent)--优先级队列

一、如何查看线程的id和名字

方法介绍:
    threading.current_thread().getName()  #查看线程的名字
    threading.current_thread().ident  #查看线程的id
    threading.enumerate(): 返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程。
    threading.activeCount(): 返回正在运行的线程数量,与len(threading.enumerate())有相同的结果。
import threading
import time
from threading import Thread,current_thread
def f1(n):
    pass
    # time.sleep(1)
    # print("子线程名字",current_thread().getName())
    # print("%s号线程的任务"%n)
if __name__ == '__main__':
    t1 = Thread(target=f1,args=(1,))
    t1.start()
    print("主线程名字",current_thread().getName())  #查看线程的名字
    print("主线程id",current_thread().ident())  #查看线程的id
    print(current_thread())  #打印结果为线程的名字
    print(threading.enumerate())  #返回包含正在运行的线程的list
    print(threading.activeCount())  #返回正在运行的线程的数量

二、线程池

线程池的作用:
    服务开启的进程数或者线程数都会随着并发的额客户端数目的增多而增多,这会对服务器主机带来巨大的压力,甚至于不堪重负而瘫痪,所以我们必须对服务开启的进程数或线程数加以控制.
线程池个数默认是 cpu个数*5,开启线程池和进程池,就一个模块的名字不一样,其他方法都一样,之前学的pool方法开启进程池是一种补充.
concurrent.futures  #需要导入的模块 (模块提供了高度封装的异步调用接口)
ThreadPoolExecutor #线程池(提供异步调用)

ProcessPoolExecutor #进程池(提供异步调用)
基本方法:
submit() #给线程池异步提交任务
   p = ThreadPoolExecutor(4) #默认的线程个数是cpu个数*5
   p.map(f1,可迭代的对象) #异步执行,map 取代for 循环submit的操作

   shutdown()#锁定线程池,等待线程池中所有以提交任务全部执行完毕. 相当于进程池的pool.close()+pool.join()
   add_done_callback(fn) #回调函数
   res.result() #取得结果,获取返回值,和get方法一样,如果没有返回值,会等待,阻塞程序
注意:

  submit和map必须在shutdown之前
#开启线程池
from
concurrent.futures import ThreadPoolExecutor def f1(n): return n*n if __name__ == '__main__': tp = ThreadPoolExecutor(4)
   tp.map(f1,range(10)) #异步提交任务,参数同样是任务名称,可迭代对象 res_list
= [] for i in range(10): res = tp.submit(f1,i) #submit是给线程池异步提交任务 res_list.append(res) tp.shutdown() #主线程等待所有提交给线程池的任务,全部执行完毕(相当于close+join) for r in res_list: print(r.result()) print("主线程结束")
#创建进程
from
concurrent.futures import ProcessPoolExecutor def f1(n): return n*n if __name__ == '__main__': tp = ProcessPoolExecutor(4) # tp.map(f1,range(10)) #异步提交任务,参数同样是任务名称,可迭代对象 res_list = [] for i in range(10): res = tp.submit(f1,i) #submit是给线程池异步提交任务 res_list.append(res) tp.shutdown() #主线程等待所有提交给线程池的任务,全部执行完毕(相当于close+join) for r in res_list: print(r.result()) print("主进程结束")

 线程池的回调函数

from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor
def f1(n,s):
    return n+s
def f2(n):
    print("回调函数>>",n.result()) #此处加result是取里面值,否则出来的是一个结果集地址
if __name__ == '__main__':
    tp = ThreadPoolExecutor(4)
    res = tp.submit(f1,11,12).add_done_callback(f2)

 三、协程 gevent

什么是协程:
    单线程下的并发称为协程\微线程\纤程.协程是一种用户态的轻量级线程,即协程是由用户程序自己控制调度
注意:
    1.python 的线程属于内核级别的,即由操作系统的控制调用(如单线程遇到IO或者执行时间过长
就会被迫交出cpu执行权限,切换其他线程执行)
    2.单线程内开启协程,一旦遇到IO,就会从应用程序级别(而非操作系统)控制切换,一次来提升效率)(非IO操作的切换与效率无关)
缺点:
    1.协程的本质是单线程下,无法利用多核,可以是一个程序开启多个进程,每个进程内开启多个线程,每个线程内开启协程
    2.协程指的是单个线程,因而一旦协程出现阻塞,将会阻塞整个线程
什么是gevent:
    gevent是一个第三方库,可以实现并发同步或异步编程,一个协程遇到IO操作自动切换到其他协程.
参数介绍:
g1 = gevent.spawn(func2,1)#创建一个协程对象g1,参数1是函数名,后面的参数都是传递给该函数的形参.
gevent.joinall([g1,g2])  #相当于g1.join()和g2.join()
g1.value #拿到func1的返回值
如何确定是一个协程,验证它在一个线程里面,而没有开启其他线程:
print(threading.current_thread().getName())  #放在线程里面,返回的值是DummyThread-n,即假线程,是一个协程
具体操作:
遇到IO会自动切换任务
import gevent
from gevent import monkey;monkey.patch_all() #可以理解为给gevent打补丁,让它能够知道time.sleep(2)跟gevent.sleep(2)一样,该补丁必须放在打补丁的前面,如time,socket模块之前.def eat(name):
    print("%seat 1"%name)
    time.sleep(2)
    print("%s eat 2"%name)
def play(name):
    print("%s play 1"%name)
    time.sleep(1)
    print("%s play 2"%name)
g1 = gevent.spawn(eat,"egon")
g2 = gevent.spawn(play,name="egon")
gevent.joinall([g1,g2]) #gevent.joinall([g1,g2]) = g1.join()和g2.join()
print("")
打印结果:
egoneat 1
egon play 1
egon play 2
egon eat 2

四、greenlet模块

如果我们在单个线程你有20个任务,想要实现在多个任务之间切换,使用yield生成器的方式过于麻烦(需要初始化一次生成器,然后再调用send...非常麻烦),而使用greenlet模块可以非常简单的实现这20个任务直接的切换.

但是在没有IO的情况下或者没有重复开辟的内存空间的操作,反而会降低程序的执行速度.

greenlet只是提供了一种比generator更加便捷的切换方式.当切到一个任务执行时遇到IO,就原地阻塞,仍然没有解决遇到IO自动切换来提升效率的问题

五、先进后出和优先级队列

先进后出队列:
  queue.LifoQueue() #先进后出队列   注意:先进去的,最后出来
优先级队列:
  queue,priorityQueue() #存储数据时可设置优先级的队列
  注意:put 的数据是一个元组,元组的第一个参数是优先级数字,数字越小,优先级越高,越先被get到取出来,第二个参数是put进去的的值1
   如果优先级相同,将会比较值,值不能是字典数据类型.
#先进后出实例
import queue
q=queue.LifoQueue() #队列,类似于栈,栈我们提过吗,是不是先进后出的顺序啊
q.put('first')
q.put('second')
# q.put_nowait()

print(q.get())
print(q.get())
# q.get_nowait()
'''
结果(后进先出):
third
second
first
'''
 
#优先级队列演示
import queue q = queue.PriorityQueue(5) #注意队列的长度,因为后面put多了,会阻塞 q.put((9,"小黑")) q.put((6,"大黑")) q.put((7,"不黑")) #如果优先级数字相同,会比较第二个参数的元素的ascii表中的位置,如果数据类型不同会报错.
q.put((7,"很黑")) print(q.get()) print(q.get()) print(q.get())

猜你喜欢

转载自www.cnblogs.com/lgw1171435560/p/10266263.html
今日推荐