线程是属于进程的,线程运行在进程空间内,同一进程所产生的线程共享同一内存空间,当进程退出时该进程所产生的线程都会被强制退出并清除。线程可与属于同一进程的其它线程共享进程所拥有的所有资源,可是其自己基本上不拥有系统资源,只拥有一点在运行中必不可少的信息(如程序计数器、一组寄存器和栈)。html
进程就是一个程序在一个数据集上的一次动态执行过程。 进程通常由程序、数据集、进程控制块三部分组成。咱们编写的程序用来描述进程要完成哪些功能以及如何完成;数据集则是程序在执行过程当中所须要使用的资源;进程控制块用来记录进程的外部特征,描述进程的执行变化过程,系统能够利用它来控制和管理进程,它是系统感知进程存在的惟一标志。python
进程和线程的目的:提升执行效率git
一、单进程单线程,主进程、主线程
二、自定义线程:
主进程
主线程
子线程github
建立多进程,目的是为了利用CPU的多核,让CPU同时执行多个任务。编程
进程:
优势:同时利用多个CPU,可以同时进行多个操做
缺点:耗费资源(建立时从新开辟内存空间)api
线程:
优势:共享同一进程内存,IO操做时,不依赖CPU,可并发操做
缺点:抢占资源浏览器
进程、线程越多越好吗?
进程不是越多越好,通常而言,CPU个数 = 进程个数
线程数,依赖任务而定,不是越多越好,每次记录线程的请求信息,上下文切换耗时。安全
IO密集型操做(不用CPU):多线程
计算密集型操做(使用CPU):多进程网络
python的进程上有个GIL 全局解释性锁,这个会形成,一个进程的多个线程,不能同时使用多个cpu,而是cpu每次只能选一个线程执行,所以,多线程在cpu执行的是无效的。可是在I/O操做的时候是能够同步的,好比time.sleep就是io 操做,多线程,能够同时等待多线程
主线程
好比咱们写的py文件,执行的时候,全部代码是如何向下执行呢?确定有个主线程的。
再咱们建立多线程时候,这些线程都是子线程,那确定有个主线程的。
进程和程序关系 进程:程序实例,程序子集,有所谓生命周期,能够kill掉,好比你安装的word,是一个程序,你打开一个文档是一个进程,能够关掉。 进程要想完成并发执行的功能,就要进程切换。进程切换,上下文切换,运行进程,说明在cpu的寄存器里面有数据了。
Python的多线程或多进程的调度是经过操做系统的调度程序实现的。当一个线程或进程阻塞,例如等待IO时,该线程或进程被操做系统下降执行的优先级,CPU内核能够被分配用来执行其它有实际计算任务的线程或进程。
Python的线程或进程架构:
线程存在于进程以内。一个进程能够包含多个线程,但一般包含至少一个线程,这个线程被称为主线程。在一个进程内的线程共享进程的内存,因此进程内的不一样线程的通讯能够经过引用共享的对象来实现。不一样的进程并不共享同一块内存,因此进程间的通讯是经过其它接口如文件、sockets或特别分配的共享内存区域来实现的。
当线程须要执行操做时,它请求操做系统的线程调度程序给其分配一些CPU时间。调度程序根据各类参数来将CPU的核心分配给等待的线程,调度程序的实现根据操做系统的不一样而不一样。同一个进程中运行的不一样线程可能同时运行在不一样的CPU核心上(但CPython例外)。
Python的CPython解释器包含一个全局解释器锁Global Interpreter Lock(GIL),它的存在确保了Python进程中同时只有一个线程能够执行,即便有多个CPU核心可用。因此CPython程序中的多线程并不能经过多个cpu核心并行执行。不过,即便是这样,在等待I/O时被阻塞的线程仍然被操做系统下降执行优先级并放入背景等待,以便让真正有计算任务的线程能够执行,下图简单地描述了这个过程:
上图中的Waiting for GIL状态是某个线程已经完成了I/O,在退出阻塞状态想要开始执行时,另一个线程持有GIL,因此已经就绪的线程被强制等待。在不少的网络应用程序中,花在等待I/O上的时间比实际处理数据的时间要多得多。只要不是有很是大的并发链接数,由GIL致使的链接的线程的阻塞是相对较低的,因此对于这些网络服务程序,使用线程的方式实现并发链接,仍然是一个合适的架构。
对于操做系统来讲,一个应用就是一个进程。好比打开一个浏览器,它是一个进程;打开一个记事本,它是一个进程。每一个进程有它特定的进程号。他们共享操做系统的内存资源。进程是操做系统分配资源的最小单位。
而对于每个进程而言,好比一个视频播放器,它必须同时播放视频和音频,就至少须要同时运行两个“子任务”,进程内的这些子任务就是经过线程来完成。线程是计算机执行任务的最小单元。一个进程它能够包含多个线程,这些线程相互独立,同时又共享进程所拥有的资源。
以使用OS资源的角度来讲,进程比线程更加“重量级”,建立一个新的进程须要的时间比建立一个新线程来讲要多,并且进程使用更多的内存资源。
有一点须要注意的是,若是你须要执行一个计算任务密集的Python程序,最好是经过多进程来实现。由于若是程序中的每一个线程都有繁重的计算任务,它们都要使用CPU,而因为GIL的存在,这些线程并不能真正的在不一样的CPU核心上并行执行,因此这会严重下降程序总体的性能。
Python中的多线程通常是经过其内置的threading模块提供的接口来实现的,多进程是经过multiprocessing模块实现的。本篇的代码实例是基于Python3的。
Python多进程编程
在Python中,经过multiprocessing模块内的Process类来建立新的进程。例如:
from multiprocessing import Process import os def info(title): print(title) print('module name:', __name__) if hasattr(os, 'getppid'): # only available on Unix print('parent process:', os.getppid()) print('process id:', os.getpid()) def f(name): info('function f') print('hello', name) if __name__ == '__main__': info('main line') p = Process(target=f, args=('bob',)) p.start() p.join() """ main line module name: __main__ parent process: 2128 process id: 3688 function f module name: __mp_main__ parent process: 3688 process id: 6884 hello bob """
经过Process类中的start方法来启动新的进程。有三种不一样的启动方式:spawn,fork和forkserver。这三种方式的详细区别请参考官方文档。
Process类中的join方法的做用是等待子进程结束后再继续往下执行。
multiprocessing模块内包括两种进程间通讯的方式:Queues和Pipes;同时也提供了其它方式在进程间共享状态,不过官方文档也提到在并发程序设计中尽可能避免这种方式。
先来看一下Queues的例子:
from multiprocessing import Process, Queue def f(q): q.put([42, None, 'hello']) if __name__ == '__main__': q = Queue() p = Process(target=f, args=(q,)) p.start() print(q.get()) # prints "[42, None, 'hello']" p.join() """ [42, None, 'hello'] """
multiprocessing模块中的Queue几乎是queue.Queue的克隆,而且Queues是线程和进程安全的,这意味着多个线程或进程访问同一个Queue实例时,不会出现数据混乱的情况。下面来看一个使用Pipe的例子:
from multiprocessing import Process, Pipe def f(conn): conn.send([42, None, 'hello']) conn.close() if __name__ == '__main__': parent_conn, child_conn = Pipe() p = Process(target=f, args=(child_conn,)) p.start() print(parent_conn.recv()) # prints "[42, None, 'hello']" p.join() """ [42, None, 'hello'] """
Pipe方法返回一对链接对象,表明管道的两端,每一个链接对象都有send()和recv()方法。若是不一样的进程(或线程)在同一时刻试图在管道的同一端进行读写,数据可能会出现混乱,在不一样端是没有问题的。Python中的对象大部分都不是进程(或线程)安全的,因此在不一样的进程(或线程)操做同一对象时,须要使用同步机制。
进程的同步是经过Lock实现的。实例以下:
from multiprocessing import Process, Lock def f(l, i): l.acquire() try: print('hello world', i) finally: l.release() if __name__ == '__main__': lock = Lock() for num in range(10): Process(target=f, args=(lock, num)).start() """ hello world 1 hello world 3 hello world 0 hello world 2 hello world 7 hello world 6 hello world 4 hello world 8 hello world 9 hello world 5 """
Pool类提供了一个批量建立多个子进程的方法,能够给定子进程数的上限,避免无限地消耗系统的资源。看一下官方文档的实例:
from multiprocessing import Pool, TimeoutError import time import os def f(x): return x*x if __name__ == '__main__': # start 4 worker processes with Pool(processes=4) as pool: # print "[0, 1, 4,..., 81]" print(pool.map(f, range(10))) # print same numbers in arbitrary order for i in pool.imap_unordered(f, range(10)): print(i) # evaluate "f(20)" asynchronously res = pool.apply_async(f, (20,)) # runs in *only* one process print(res.get(timeout=1)) # prints "400" # evaluate "os.getpid()" asynchronously res = pool.apply_async(os.getpid, ()) # runs in *only* one process print(res.get(timeout=1)) # prints the PID of that process # launching multiple evaluations asynchronously *may* use more processes multiple_results = [pool.apply_async(os.getpid, ()) for i in range(4)] print([res.get(timeout=1) for res in multiple_results]) # make a single worker sleep for 10 secs res = pool.apply_async(time.sleep, (10,)) try: print(res.get(timeout=1)) except TimeoutError: print("We lacked patience and got a multiprocessing.TimeoutError") print("For the moment, the pool remains available for more work") # exiting the 'with'-block has stopped the pool print("Now the pool is closed and no longer available") """ [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] 0 1 4 9 16 25 36 49 64 81 400 8652 [8652, 8652, 8652, 8652] We lacked patience and got a multiprocessing.TimeoutError For the moment, the pool remains available for more work Now the pool is closed and no longer available """
Python中使用线程的方式有不少都与使用进程的方式相似,这里就再也不列出实例代码。
在Python中,经过threading模块内的Thread类来建立新的进程。经过Thread类中的start方法启动线程,join方法等待线程结束。
线程间最简单的通讯方式是经过threading模块内的Event类。固然也能够经过共享对象来在线程间共享状态信息。因为queue.Queue是线程和进程安全的,因此它也是线程通讯使用理想对象。其它对象大部分都不是线程(或进程)安全的,因此在不一样的线程(或进程)操做同一对象时,须要使用同步机制。
threading模块中提供了Lock,RLock,Condition,Semaphore等类进行线程间的同步。
关于threading模块中更详细的使用信息,请参考官方文档。
内容来源与参考:
https://andyyoung01.github.io/2017/01/21/Python%E7%9A%84%E5%A4%9A%E7%BA%BF%E7%A8%8B%E4%B8%8E%E5%A4%9A%E8%BF%9B%E7%A8%8B%E7%AE%80%E4%BB%8B-%E4%B8%8A/#Python的线程和GIL
https://andyyoung01.github.io/2017/01/22/Python%E7%9A%84%E5%A4%9A%E7%BA%BF%E7%A8%8B%E4%B8%8E%E5%A4%9A%E8%BF%9B%E7%A8%8B%E7%AE%80%E4%BB%8B-%E4%B8%8B/
threading 模块创建在 _thread 模块之上。thread 模块以低级、原始的方式来处理和控制线程,而 threading 模块经过对 thread 进行二次封装,提供了更方便的 api 来处理线程。
threading基于Java的线程模型设计。锁(Lock)和条件变量(Condition)在Java中是对象的基本行为(每个对象都自带了锁和条件变量),而在Python中则是独立的对象,因此python的threading模块中还提供了Lock,Rlock,Condition,Event等经常使用类,它们在python中是独立于Tread模块的,可是却与线程紧密相关,不可分割。
须要注意的是:python的线程中没有优先级、线程组,也不能被中止、暂停、恢复、中断,线程只能随着线程中的代码执行完毕而被销毁。在实现线程池的时候没法中止已经注入了方法且执行超时的线程。
import threading import time def worker(num): time.sleep(3) print("Thread %d" % num) return for i in range(5): t = threading.Thread(target=worker, args=(i,)) t.start() """ Thread 0 Thread 1 Thread 2 Thread 4 Thread 3 """
import threading import time class MyThread(threading.Thread): def __init__(self, name): # threading.Thread.__init__(self) super(MyThread, self).__init__(target=self.fun, name="t %d" % i) self.name = name def fun(self): time.sleep(2) print("name %s thread %s" % (self.name, threading.current_thread().name)) for i in range(5): t = MyThread(i) t.start() """ name 0 thread 0 name 2 thread 2 name 1 thread 1 name 4 thread 4 name 3 thread 3 """
t.start() : 激活线程,
t.getName() : 获取线程的名称
t.setName() : 设置线程的名称
t.name : 获取或设置线程的名称
t.is_alive() : 判断线程是否为激活状态
t.isAlive() :判断线程是否为激活状态
t.setDaemon() 设置为后台线程或前台线程(默认:False);经过一个布尔值设置线程是否为守护线程,必须在执行start()方法以后才可使用。若是是后台线程,主线程执行过程当中,后台线程也在进行,主线程执行完毕后,后台线程不论成功与否,均中止;若是是前台线程,主线程执行过程当中,前台线程也在进行,主线程执行完毕后,等待前台线程也执行完成后,程序中止
t.isDaemon() : 判断是否为守护线程
t.ident :获取线程的标识符。线程标识符是一个非零整数,只有在调用了start()方法以后该属性才有效,不然它只返回None。
t.join() :逐个执行每一个线程,执行完毕后继续往下执行,该方法使得多线程变得无心义
t.run() :线程被cpu调度后自动执行线程对象的run方法
join 代码
import time import threading def printNum(a): print('num:',a) time.sleep(1) def ThreadTest(i): return threading.Thread(target=printNum, args=(999,)) thread_arr = [] for i in range(5): t = ThreadTest(i) thread_arr.append(t) for t in thread_arr: t.start() for t in thread_arr: t.join() print('finished') """ num: 999 num: 999 num: 999 num: 999 num: 999 finished """
threading用于提供线程相关的操做,线程是应用程序中工做的最小单元。python当前版本的多线程库没有实现优先级、线程组,线程也不能被中止、暂停、恢复、中断。
threading模块提供的类:
Thread, Lock, Rlock, Condition, [Bounded]Semaphore, Event, Timer, local。
threading 模块提供的经常使用方法:
threading.currentThread(): 返回当前的线程变量。
threading.enumerate(): 返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程。
threading.activeCount(): 返回正在运行的线程数量,与len(threading.enumerate())有相同的结果。
threading 模块提供的常量:
threading.TIMEOUT_MAX 设置threading全局超时时间。
Thread是线程类,有两种使用方法,直接传入要运行的方法或从Thread继承并覆盖run():
import threading import time # 方法一:将要执行的方法做为参数传给Thread的构造方法 def action(arg): time.sleep(1) print('the arg is:%s\r' % arg) for i in range(4): t = threading.Thread(target=action, args=(i,)) t.start() print('main thread end!') """ main thread end! the arg is:0 the arg is:3 """ # 方法二:从Thread继承,并重写run() class MyThread(threading.Thread): def __init__(self, arg): super(MyThread, self).__init__() # 注意:必定要显式的调用父类的初始化函数。 self.arg = arg def run(self): # 定义每一个线程要运行的函数 time.sleep(1) print('the arg is:%s\r' % self.arg) for i in range(4): t = MyThread(i) t.start() print('main thread end!') """ main thread end! the arg is:1 the arg is:2 the arg is:3 """
因为线程之间随机调度:某线程可能在执行n条后,CPU接着执行其余线程。为了多个线程同时操做一个内存中的资源时不产生混乱,咱们使用锁。
Lock(指令锁)是可用的最低级的同步指令。Lock处于锁定状态时,不被特定的线程拥有。Lock包含两种状态——锁定和非锁定,以及两个基本的方法。
能够认为Lock有一个锁定池,当线程请求锁定时,将线程置于池中,直到得到锁定后出池。池中的线程处于状态图中的同步阻塞状态。
RLock(可重入锁)是一个能够被同一个线程请求屡次的同步指令。RLock使用了“拥有的线程”和“递归等级”的概念,处于锁定状态时,RLock被某个线程拥有。拥有RLock的线程能够再次调用acquire(),释放锁时须要调用release()相同次数。
能够认为RLock包含一个锁定池和一个初始值为0的计数器,每次成功调用 acquire()/release(),计数器将+1/-1,为0时锁处于未锁定状态。
简言之:Lock属于全局,Rlock属于线程。
构造方法:
Lock(),Rlock(),推荐使用Rlock()
实例方法:
acquire([timeout]): 尝试得到锁定。使线程进入同步阻塞状态。
release(): 释放锁。使用前线程必须已得到锁定,不然将抛出异常。
线程锁threading.RLock和threading.Lock
咱们使用线程对数据进行操做的时候,若是多个线程同时修改某个数据,可能会出现不可预料的结果,为了保证数据的准确性,引入了锁的概念。
例:假设列表A的全部元素就为0,当一个线程从前向后打印列表的全部元素,另一个线程则从后向前修改列表的元素为1,那么输出的时候,列表的元素就会一部分为0,一部分为1,这就致使了数据的不一致。锁的出现解决了这个问题。
View Code
Lock与Rlock 对比
import threading lock = threading.Lock() #Lock对象 lock.acquire() lock.acquire() #产生了死锁。 lock.release() lock.release() import threading rLock = threading.RLock() #RLock对象 rLock.acquire() rLock.acquire() #在同一线程内,程序不会堵塞。 rLock.release() rLock.release() lock vs rlock Code
未使用锁
屡次运行可能产生混乱。这种场景就是适合使用锁的场景。
import threading import time gl_num = 0 def show(arg): global gl_num time.sleep(0.00001) gl_num += 1 print(gl_num) for i in range(5): t = threading.Thread(target=show, args=(i,)) t.start() print('main thread stop') """ 1 2 3 main thread stop 4 5 """
使用锁
全局变量在每次被调用时都要得到锁,才能操做,所以保证了共享数据的安全性。
import threading import time gl_num = 0 lock = threading.RLock() # 调用acquire([timeout])时,线程将一直阻塞,直到得到锁定或者直到timeout秒后(timeout参数可选)。 # 返回是否得到锁。 def Func(): lock.acquire() global gl_num gl_num += 1 time.sleep(0.00001) print(gl_num) lock.release() for i in range(5): t = threading.Thread(target=Func) t.start() """ 1 2 3 4 5 """
条件变量对象能让一个线程停下来,等待其它线程知足了某个“条件”。如,状态的改变或值的改变。
Condition(条件变量)一般与一个锁关联。须要在多个Contidion中共享一个锁时,能够传递一个Lock/RLock实例给构造方法,不然它将本身生成一个RLock实例。
能够认为,除了Lock带有的锁定池外,Condition还包含一个等待池,池中的线程处于等待阻塞状态,直到另外一个线程调用notify()/notifyAll()通知;获得通知后线程进入锁定池等待锁定。
一个condition变量老是与某些类型的锁相联系,这个可使用默认的状况或建立一个,当几个condition变量必须共享和同一个锁的时候,是颇有用的。锁是conditon对象的一部分:没有必要分别跟踪。
condition变量服从上下文管理协议:with语句块封闭以前能够获取与锁的联系。 acquire() 和 release() 会调用与锁相关联的相应的方法。
其余和锁关联的方法必须被调用,wait()方法会释放锁,当另一个线程使用 notify() or notify_all()唤醒它以前会一直阻塞。一旦被唤醒,wait()会从新得到锁并返回
Condition(lock=None)
构造方法:
Condition([lock/rlock])
实例方法:
比较经典的例子是生产者与消费者模型,代码中写了两个类,Consumer和Producer,分别继承了Thread类,分别初始化这两个类得到了c和p对象,并启动这两个线程。则这两个线程去执行run方法(这里与Thread类内部的调度有关),定义了producer全局变量和condition对象为全局变量,当producer不大于1时,消费者线程被condition对象阻塞,不能继续消费(这里是再也不递减),当producer不小于10时,生产者线程被condition对象阻塞,再也不生产(这里是再也不累加),代码在下面,拿去执行,断点一下就明白了。
import threading import time condition = threading.Condition() products = 0 class Producer(threading.Thread): def __init__(self): threading.Thread.__init__(self) def run(self): global condition, products while True: if condition.acquire(): if products < 10: products += 1; print("Producer(%s):deliver one, now products:%s" %(self.name, products)) condition.notify() else: print("Producer(%s):already 10, stop deliver, now products:%s" %(self.name, products)) condition.wait(); condition.release() time.sleep(2) class Consumer(threading.Thread): def __init__(self): threading.Thread.__init__(self) def run(self): global condition, products while True: if condition.acquire(): if products > 1: products -= 1 print("Consumer(%s):consume one, now products:%s" %(self.name, products)) condition.notify() else: print("Consumer(%s):only 1, stop consume, products:%s" %(self.name, products)) condition.wait(); condition.release() time.sleep(2) if __name__ == "__main__": for p in range(0, 2): p = Producer() p.start() for c in range(0, 10): c = Consumer() c.start() """ Producer(Thread-1):deliver one, now products:1 Producer(Thread-2):deliver one, now products:2 Consumer(Thread-3):consume one, now products:1 Consumer(Thread-4):only 1, stop consume, products:1 Consumer(Thread-5):only 1, stop consume, products:1 ..... """
通用的条件变量。多个线程能够等待某个事件的发生,在事件发生后,全部的线程都会被激活。
Event(事件)是最简单的线程通讯机制之一:一个线程通知事件,其余线程等待事件。Event内置了一个初始为False的标志,当调用set()时设为True,调用clear()时重置为 False。wait()将阻塞线程至等待阻塞状态。
Event其实就是一个简化版的 Condition。Event没有锁,没法使线程进入同步阻塞状态。
构造方法:
Event()
实例方法:
这是一个比较关键的类,它的意义在于能够控制属于同一个线程类的多个实例化对象,让他们同时阻塞或者执行。配合队列来实现一个线程池很是好用。
import threading import time import random def light(): if not event.isSet(): #没有设置的话 event.set() # 设置绿灯 count = 0 #计数器秒数 while True: if count < 10: #小于十秒 是绿灯 print("\033[42;1m ------green light on ----\033[0m") elif count < 13: #小于13秒 大于10秒 是黄灯 print("\033[43;1m ------yellow light on ----\033[0m") elif count < 20: #小于于20秒 有设置则取消 if event.isSet(): event.clear() print("\033[41;1m ------red light on ----\033[0m") else: #大于20 从新 count = 0 #取消秒数计时 event.set() #从新变为绿灯 time.sleep(1) count +=1 def car(n): # 第二个线程 车线程 while 1: time.sleep(random.randrange(3)) #随机等待三秒 if event.isSet(): print("car [%s] is running..." % n) #若是被设置了信号则是绿灯,该线程的车便可经过 else: #不然的话提示红灯 print("car [%s] is waitting for the red light.." %n) event.wait() #红灯的话,会在此处卡住,不往下执行 print("Green light is on ,car %s is running......." %n) if __name__ == '__main__': #下面是定义了两个线程 ,灯线程 车线程, threading.Event用来设置标着符号让两个线程交流 event = threading.Event() Light = threading.Thread(target=light) Light.start() for i in range(3): t = threading.Thread(target=car,args=(i,)) t.start() """ ------green light on ---- car [2] is running... car [0] is running... ------yellow light on ---- car [1] is running... car [1] is running... car [2] is running... car [0] is running... ------red light on ---- car [1] is waitting for the red light.. ...... """
Queue 就是对队列,它是线程安全的
举例来讲,咱们去肯德基吃饭。厨房是给咱们作饭的地方,前台负责把厨房作好的饭卖给顾客,顾客则去前台领取作好的饭。这里的前台就至关于咱们的队列。
这个模型也叫生产者-消费者模型。
import queue q = queue.Queue(maxsize=0) # 构造一个先进先出队列,maxsize指定队列长度,为0 时,表示队列长度无限制。 q.join() # 等到队列为空的时候,再执行别的操做 q.qsize() # 返回队列的大小 (不可靠) q.empty() # 当队列为空的时候,返回True 不然返回False (不可靠) q.full() # 当队列满的时候,返回True,不然返回False (不可靠) q.put(item, block=True, timeout=None) # 将item放入Queue尾部,item必须存在,能够参数block默认为True,表示当队列满时,会等待队列给出可用位置。为False时为非阻塞,此时若是队列已满,会引起queue.Full 异常。 可选参数timeout,表示 会阻塞设置的时间,事后,若是队列没法给出放入item的位置,则引起 queue.Full 异常 q.get(block=True, timeout=None) # 移除并返回队列头部的一个值,可选参数block默认为True,表示获取值的时候,若是队列为空,则阻塞,为False时,不阻塞,若此时队列为空,则引起 queue.Empty异常。 可选参数timeout,表示会阻塞设置的时候,事后,若是队列为空,则引起Empty异常。 q.put_nowait(item) # 等效于 put(item,block=False) q.get_nowait() # 等效于 get(item,block=False)