一、进程和线程

1.进程假如有两个程序A和B,程序A在执行到一半的过程中,需要读取大量的数据输入(I/O操作),而此时CPU只能静静地等待任务A读取完数据才能继续执行,这样就白白浪费了CPU资源。是不是在程序A读取数据的过程中,让程序B去执行,当程序A读取完数据之后,让

程序B暂停,然后让程序A继续执行?当然没问题,但这里有一个关键词:切换既然是切换,那么这就涉及到了状态的保存,状态的恢复,加上程序A与程序B所需要的系统资源(内存,硬盘,键盘等等)是不一样的。自然而然的就需要有一个东西去记录程序A和程序B

分别需要什么资源,怎样去识别程序A和程序B等等,所以就有了一个叫进程的抽象进程定义:

进程就是一个程序在一个数据集上的一次动态执行过程。进程一般由程序、数据集、进程控制块三部分组成。我们编写的程序用来描述进程要完成哪些功能以及如何完成;数据集则是程序在执行过程中所需要使用的资源;进程控制块用来记录进程的外部特征,描述进程的执行变化过程,系统可以利用它来控制和管理进程,它是系

统感知进程存在的唯一标志。

举一例说明进程:

想象一位有一手好厨艺的计算机科学家正在为他的女儿烘制生日蛋糕。他有做生日蛋糕的食谱,厨房里有所需的原料:面粉、鸡蛋、糖、香草汁等。在这个比喻中,做蛋糕的食谱就是程序(即用适当形式描述的算法)计算机科学家就是处理器(cpu),

而做蛋糕的各种原料就是输入数据。进程就是厨师阅读食谱、取来各种原料以及烘制蛋糕等一系列动作的总和。现在假设计算机科学家的儿子哭着跑了进来,说他的头被一只蜜蜂蛰了。计算机科学家就记录下他照着食谱做到哪儿了(保存进程的当前状态),然后拿出一本急救手册,按照其中的指示处理蛰伤。这里,

我们看到处理机从一个进程(做蛋糕)切换到另一个高优先级的进程(实施医疗救治),每个进程拥有各自的程序(食谱和急救手册)。当蜜蜂蛰伤处理完之后,这位计算机科学家又回来做蛋糕,从他离开时的那一步继续做下去。

2.线程线程的出现是为了降低上下文切换的消耗,提高系统的并发性,并突破一个进程只能干一样事的缺陷,使到进程内并发成为可能。

假设,一个文本程序,需要接受键盘输入,将内容显示在屏幕上,还需要保存信息到硬盘中。若只有一个进程,势必造成同一时间只能干一样事的尴尬(当保存时,就不能通过键盘输入内容)。若有多个进程,每个进程负责一个任务,进程A负责接收键盘输入的任务,进程B负责将内容显示在屏幕上的任务,

进程C负责保存内容到硬盘中的任务。这里进程A,B,C间的协作涉及到了进程通信问题,而且有共同都需要拥有的东西-------文本内容,不停的切换造成性能上的损失。若有一种机制,可以使

任务A,B,C共享资源,这样上下文切换所需要保存和恢复的内容就少了,同时又可以减少通信所带来的性能损耗,那就好了。是的,这种机制就是线程。

线程也叫轻量级进程,它是一个基本的CPU执行单元,也是程序执行过程中的最小单元,由线程ID、程序

计数器、寄存器集合和堆栈共同组成。线程的引入减小了程序并发执行时的开销,提高了操作系统的并发

性能。线程没有自己的系统资源。Threads share the address space of the process that created it; processes have their own address space.

Threads have direct access to the data segment of its process; processes have their own copy of the data segment of the parent process.

Threads can directly communicate with other threads of its process; processes must use interprocess communication to communicate with sibling processes.

New threads are easily created; new processes require duplication of the parent process.

Threads can exercise considerable control over threads of the same process; processes can only exercise control over child processes.

Changes to the main thread (cancellation, priority change, etc.) may affect the behavior of the other threads of the process; changes to the parent process does not affect child processes.1 一个程序至少有一个进程,一个进程至少有一个线程.(进程可以理解成线程的容器)

2 进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率。

3 线程在执行过程中与进程还是有区别的。每个独立的线程有一个程序运行的入口、顺序执行序列和

程序的出口。但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。

4 进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调

度的一个独立单位.

线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈)但是

它可与同属一个进程的其他的线程共享进程所拥有的全部资源.

一个线程可以创建和撤销另一个线程;同一个进程中的多个线程之间可以并发执行.

python的GIL(全局解释锁)

In CPython, the global interpreter lock, or GIL, is a mutex that prevents multiple native threads from executing Python bytecodes at once. This lock is necessary mainly because CPython’s memory management is not thread-safe. (However, since the GIL exists, other features have grown to depend on the guarantees that it enforces.)

上面的核心意思就是,无论你启多少个线程,你有多少个cpu, Python在执行的时候会在同一时刻只允许一个线程运行

二、

1.线程的两种调用方式

threading 模块建立在thread 模块之上。thread模块以低级、原始的方式来处理和控制线程,而threading 模块通过对thread进行二次封装,提供了更方便的api来处理线程。

直接调用:

import threadingimport time

def sayhi(num): #定义每个线程要运行的函数

print("running on number:%s" %num)

time.sleep(3)

if __name__ == '__main__':

t1 = threading.Thread(target=sayhi,args=(1,)) #生成一个线程实例

t2 = threading.Thread(target=sayhi,args=(2,)) #生成另一个线程实例

t1.start() #启动线程

t2.start() #启动另一个线程

print(t1.getName()) #获取线程名

print(t2.getName())

继承式调用:

import threadingimport timeclass MyThread(threading.Thread):    def __init__(self,num):

threading.Thread.__init__(self)

self.num = num    def run(self):#定义每个线程要运行的函数

print("running on number:%s" %self.num)

time.sleep(3)if __name__ == '__main__':

t1 = MyThread(1)

t2 = MyThread(2)

t1.start()

t2.start()

print("ending......")

2.threading.thread的实例方法

join&Daemon方法

import threadingfrom time import ctime,sleepimport timedef ListenMusic(name):        print ("Begin listening to %s. %s" %(name,ctime()))

sleep(3)        print("end listening %s"%ctime())def RecordBlog(title):        print ("Begin recording the %s! %s" %(title,ctime()))

sleep(5)        print('end recording %s'%ctime())

threads = []

t1 = threading.Thread(target=ListenMusic,args=('水手',))

t2 = threading.Thread(target=RecordBlog,args=('python线程',))

threads.append(t1)

threads.append(t2)if __name__ == '__main__':    for t in threads:        #t.setDaemon(True) #注意:一定在start之前设置        t.start()        # t.join()

# t1.join()    t1.setDaemon(True)    #t2.join()########考虑这三种join位置下的结果?

print ("all over %s" %ctime())

join():在子线程完成运行之前,这个子线程的父线程将一直被阻塞。

setDaemon(True):

将线程声明为守护线程,必须在start() 方法调用之前设置, 如果不设置为守护线程程序会被无限挂起。这个方法基本和join是相反的。

当我们 在程序运行中,执行一个主线程,如果主线程又创建一个子线程,主线程和子线程 就分兵两路,分别运行,那么当主线程完成想退出时,会检验子线程是否完成。如 果子线程未完成,则主线程会等待子线程完成后再退出。但是有时候我们需要的是 只要主线程完成了,不管子线程是否完成,都要和主线程一起退出,这时就可以 用setDaemon方法啦.

其他方法:

# run():  线程被cpu调度后自动执行线程对象的run方法# start():启动线程活动。# isAlive(): 返回线程是否活动的。# getName(): 返回线程名。# setName(): 设置线程名。threading模块提供的一些方法:# threading.currentThread(): 返回当前的线程变量。# threading.enumerate(): 返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程。# threading.activeCount(): 返回正在运行的线程数量,与len(threading.enumerate())有相同的结果。

3.同步锁(Lock)

import timeimport threadingdef addNum():    global num #在每个线程中都获取这个全局变量

#num-=1

temp=num    #print('--get num:',num )

time.sleep(0.1)

num =temp-1 #对此公共变量进行-1操作num = 100  #设定一个共享变量thread_list = []for i in range(100):

t = threading.Thread(target=addNum)

t.start()

thread_list.append(t)for t in thread_list: #等待所有线程执行完毕    t.join()print('final num:', num )

观察:time.sleep(0.1)  /0.001/0.0000001 结果分别是多少?

多个线程都在同时操作同一个共享资源,所以造成了资源破坏,怎么办呢?(join会造成串行,失去所线程的意义)

我们可以通过同步锁来解决这种问题.

import timeimport threadingdef sub():    global num

lock.acquire()  #上锁

tmpe = num

time.sleep(0.001)

num = tmpe-1

lock.release()  #解锁num = 100l=[]

lock= threading.Lock()for i in range(100):

t = threading.Thread(target=sub)

t.start()

l.append(t)for t in l:

t.join()print(num)

4.线程死锁和递归锁

在线程间共享多个资源的时候,如果两个线程分别占有一部分资源并且同时等待对方的资源,就会造成死锁,因为系统判断这部分资源都正在使用,所有这两个线程在无外力作用下将一直等待下去。下面是一个死锁的例子:

import threadingimport timeclass MyThread(threading.Thread):    def actionA(self):

Lock.acquire()        # A.acquire()

print(self.name,'gotA',time.ctime())

time.sleep(3)

Lock.acquire()        print(self.name, 'gotB', time.ctime())

time.sleep(2)

Lock.release()

Lock.release()    def actionB(self):

Lock.acquire()        print(self.name, 'gotB', time.ctime())

time.sleep(3)

Lock.acquire()        print(self.name, 'gotA', time.ctime())

time.sleep(2)

Lock.release()

Lock.release()    def run(self):

self.actionA()

self.actionB()if __name__ == '__main__':    # A=threading.Lock()

# B=threading.Lock()

Lock = threading.Lock()

l=[]    for i in range(5):

t = MyThread()

t.start()

l.append(t)    for i in l:

i.join()    print('ending.....')

解决办法:使用递归锁,将Lock = threading.Lock()  #改为----->Lock = threading.RLock()

为了支持在同一线程中多次请求同一资源,python提供了“可重入锁”:threading.RLock。RLock内部维护着一个Lock和一个counter变量,counter记录了acquire的次数,从而使得资源可以被多次acquire。直到一个线程所有的acquire都被release,其他的线程才能获得资源。

同步条件(Event事件)

Python提供了Event对象用于线程间通信,它是由线程设置的信号标志,如果信号标志位为假,则线程等待直到信号被其他线程设置成真。这一点似乎和windows的event正好相反。 Event对象实现了简单的线程通信机制,它提供了设置信号,清除信号,等待等用于实现线程间的通信。

使用Event的set()方法可以设置Event对象内部的信号标志为真。Event对象提供了isSet()方法来判断其内部信号标志的状态,当使用event对象的set()方法后,isSet()方法返回真.

使用Event对象的clear()方法可以清除Event对象内部的信号标志,即将其设为假,当使用Event的clear方法后,isSet()方法返回假

Event对象wait的方法只有在内部信号为真的时候才会很快的执行并完成返回。当Event对象的内部信号标志位假时,则wait方法一直等待到其为真时才返回。

import threading,timeclass Boss(threading.Thread):    def run(self):        print("BOSS:今晚大家都要加班到22:00。")        print(event.isSet())

event.set()

time.sleep(5)        print("BOSS:<22:00>可以下班了。")        print(event.isSet())

event.set()class Worker(threading.Thread):    def run(self):

event.wait()        print("Worker:哎……命苦啊!")

time.sleep(1)

event.clear()

event.wait()        print("Worker:OhYeah!")if __name__=="__main__":

event=threading.Event()

threads=[]    for i in range(5):

threads.append(Worker())

threads.append(Boss())    for t in threads:

t.start()    for t in threads:

t.join()

信号量(Semaphore)

信号量用来控制线程并发数的,BoundedSemaphore或Semaphore管理一个内置的计数 器,每当调用acquire()时-1,调用release()时+1。

计数器不能小于0,当计数器为 0时,acquire()将阻塞线程至同步锁定状态,直到其他线程调用release()。(类似于停车位的概念)

BoundedSemaphore与Semaphore的唯一区别在于前者将在调用release()时检查计数 器的值是否超过了计数器的初始值,如果超过了将抛出一个异常。

import threading,timeclass myThread(threading.Thread):    def run(self):        if semaphore.acquire():            print(self.name)

time.sleep(5)

semaphore.release()if __name__=="__main__":

semaphore=threading.Semaphore(5)

thrs=[]    for i in range(100):

thrs.append(myThread())    for t in thrs:

t.start()

队列(queue)

列表是不安全的数据结构

import threading,time

li=[1,2,3,4,5]def pri():    while li:

a=li[-1]        print(a)

time.sleep(1)        try:

li.remove(a)        except Exception as e:            print('----',a,e)

t1=threading.Thread(target=pri,args=())

t1.start()

t2=threading.Thread(target=pri,args=())

t2.start()

思考:如何通过对列来完成上述功能?

queue is especially useful in threaded programming when information must be exchanged safely between multiple threads.

创建一个“队列”对象import Queue

q = Queue.Queue(maxsize = 10)

Queue.Queue类即是一个队列的同步实现。队列长度可为无限或者有限。可通过Queue的构造函数的可选参数maxsize来设定队列长度。如果maxsize小于1就表示队列长度无限。

将一个值放入队列中

q.put(10)

调用队列对象的put()方法在队尾插入一个项目。put()有两个参数,第一个item为必需的,为插入项目的值;第二个block为可选参数,默认为1。如果队列当前为空且block为1,put()方法就使调用线程暂停,直到空出一个数据单元。如果block为0,put方法将引发Full异常。

将一个值从队列中取出

q.get()

调用队列对象的get()方法从队头删除并返回一个项目。可选参数为block,默认为True。如果队列为空且block为True,

get()就使调用线程暂停,直至有项目可用。如果队列为空且block为False,队列将引发Empty异常。

Python Queue模块有三种队列及构造函数:1、Python Queue模块的FIFO队列先进先出。   class queue.Queue(maxsize)2、LIFO类似于堆,即先进后出。               class queue.LifoQueue(maxsize)3、还有一种是优先级队列级别越低越先出来。        class queue.PriorityQueue(maxsize)

此包中的常用方法(q = Queue.Queue()):

q.qsize() 返回队列的大小

q.empty() 如果队列为空,返回True,反之False

q.full() 如果队列满了,返回True,反之False

q.full 与 maxsize 大小对应

q.get([block[, timeout]]) 获取队列,timeout等待时间

q.get_nowait() 相当q.get(False)

非阻塞 q.put(item) 写入队列,timeout等待时间

q.put_nowait(item) 相当q.put(item, False)

q.task_done() 在完成一项工作之后,q.task_done() 函数向任务已经完成的队列发送一个信号

q.join() 实际上意味着等到队列为空,再执行别的操作

上诉方法的应用示例:

import queue  #线程 队列q = queue.Queue() #FIFO先进先出q.put(21)

q.put({"name":"yu"})

q.put("hello")while 1:

data = q.get()    print(data)    print('-------------')# q = queue.LifoQueue(2) #先进后出# q.put(21)# q.put({"name":"yu"})# q.put("hello")#

# while 1:#     data = q.get()#     print(data)#     print('-------------')# q = queue.PriorityQueue() #Priority优先级顺序# q.put([3,21])# q.put([1,{"name":"yu"}])# q.put([2,"hello"])#

# while 1:#     data = q.get()#     print(data[1])#     print('-------------')q = queue.Queue() #FIFO先进先出q.put(21)

q.put({"name":"yu"})

q.put("hello")while 1:    print(q.qsize())

data = q.get()    print(data)    print('-------------')    print(q.empty())    print(q.full())    print(q.qsize())

生产者消费者模型:

为什么要使用生产者和消费者模式

在线程世界里,生产者就是生产数据的线程,消费者就是消费数据的线程。在多线程开发当中,如果生产者处理速度很快,而消费者处理速度很慢,那么生产者就必须等待消费者处理完,才能继续生产数据。同样的道理,如果消费者的处理能力大于生产者,那么消费者就必须等待生产者。为了解决这个问题于是引入了生产者和消费者模式。

什么是生产者消费者模式

生产者消费者模式是通过一个容器来解决生产者和消费者的强耦合问题。生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列里取,阻塞队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力。

这就像,在餐厅,厨师做好菜,不需要直接和客户交流,而是交给前台,而客户去饭菜也不需要不找厨师,直接去前台领取即可,这也是一个结耦的过程。

import time,randomimport queue,threading

q = queue.Queue()def Producer(name):

count = 0  while count <10:    print("making........")

time.sleep(5)

q.put(count)    print('Producer %s has produced %s baozi..' %(name, count))

count +=1    #q.task_done()    q.join()    print("ok......")def Consumer(name):

count = 0  while count <10:

time.sleep(random.randrange(4))    # if not q.empty():

#     print("waiting.....")

#q.join()

data = q.get()        print("eating....")

time.sleep(4)

q.task_done()        #print(data)

print('\033[32;1mConsumer %s has eat %s baozi...\033[0m' %(name, data))    # else:

#     print("-----no baozi anymore----")

count +=1p1 = threading.Thread(target=Producer, args=('A'))

c1 = threading.Thread(target=Consumer, args=('B'))

c2 = threading.Thread(target=Consumer, args=('C'))

c3 = threading.Thread(target=Consumer, args=('D'))

p1.start()

c1.start()

c2.start()

c3.start()

三、多进程模块 multiprocessing

Multiprocessing is a package that supports spawning processes using an API similar to the threading module. The multiprocessing package offers both local and remote concurrency,effectively side-stepping the Global Interpreter Lock by using subprocesses instead of threads. Due to this, the multiprocessing module allows the programmer to fully leverage multiple processors on a given machine. It runs on both Unix and Windows.

由于GIL的存在,python中的多线程其实并不是真正的多线程,如果想要充分地使用多核CPU的资源,在python中大部分情况需要使用多进程。

multiprocessing包是Python中的多进程管理包。与threading.Thread类似,它可以利用multiprocessing.Process对象来创建一个进程。该进程可以运行在Python程序内部编写的函数。该Process对象与Thread对象的用法相同,也有start(), run(), join()的方法。此外multiprocessing包中也有Lock/Event/Semaphore/Condition类 (这些对象可以像多线程那样,通过参数传递给各个进程),用以同步进程,其用法与threading包中的同名类一致。所以,multiprocessing的很大一部份与threading使用同一套API,只不过换到了多进程的情境。

1.进程的调用

调用一:

from multiprocessing import Processimport timedef f(name):

time.sleep(2)    print('hello', name,time.ctime())if __name__ == '__main__':

p_list=[]    for i in range(3):

p = Process(target=f, args=('yu',))

p_list.append(p)

p.start()    for i in p_list:

p.join()    print('end。。。。')

调用二:

from multiprocessing import Processimport timeclass MyProcess(Process):    def __init__(self):

super(MyProcess, self).__init__()        #self.name = name

def run(self):

time.sleep(1)        print ('hello', self.name,time.ctime())if __name__ == '__main__':

p_list=[]    for i in range(3):

p = MyProcess()

p.start()

p_list.append(p)    for p in p_list:

p.join()    print('end。。。')

To show the individual process IDs involved, here is an expanded example:

将父子进程的id表达出来,进行比对,示例如下:

from multiprocessing import Processimport osimport timedef info(title):    print("title:", title)    print('parent process:', os.getppid())    print('process id:', os.getpid())def f(name):

info('function f')    print('hello', name)if __name__ == '__main__':

info('main process line')

time.sleep(1)    print("------------------")

p = Process(target=info, args=('yu',))

p.start()

p.join()

2.Process类

构造方法:

Process([group [, target [, name [, args [, kwargs]]]]])

group: 线程组,目前还没有实现,库引用中提示必须是None;

target: 要执行的方法;

name: 进程名;

args/kwargs: 要传入方法的参数。

实例方法:

is_alive():返回进程是否在运行。

join([timeout]):阻塞当前上下文环境的进程程,直到调用此方法的进程终止或到达指定的timeout(可选参数)。

start():进程准备就绪,等待CPU调度

run():strat()调用run方法,如果实例进程时未制定传入target,这star执行t默认run()方法。

terminate():不管任务是否完成,立即停止工作进程

属性:

daemon:和线程的setDeamon功能一样

name:进程名字。

pid:进程号。

import timefrom  multiprocessing import Processdef foo(i):

time.sleep(1)    print (p.is_alive(),i,p.pid)

time.sleep(1)if __name__ == '__main__':

p_list=[]    for i in range(10):

p = Process(target=foo, args=(i,))        #p.daemon=True        p_list.append(p)    for p in p_list:

p.start()    # for p in p_list:

#     p.join()

print('main process end')

3.进程间通讯

进程间队列Queue

from multiprocessing import Process, Queueimport queuedef f(q,n):    #q.put([123, 456, 'hello'])

q.put(n*n+1)    print("son process",id(q))if __name__ == '__main__':

q = Queue()  #try: q=queue.Queue()

print("main process",id(q))    for i in range(3):

p = Process(target=f, args=(q,i))

p.start()    print(q.get())    print(q.get())    print(q.get())

管道

ThePipe() function returns a pair of connection objects connected by a pipe which by default is duplex (two-way). For example:

from multiprocessing import Process, Pipedef f(conn):

conn.send([12, {"name":"yu"}, 'hello'])

response=conn.recv()    print("response",response)

conn.close()    print("q_ID2:",id(child_conn))if __name__ == '__main__':

parent_conn, child_conn = Pipe()    print("q_ID1:",id(child_conn))

p = Process(target=f, args=(child_conn,))

p.start()    print(parent_conn.recv())   # prints "[42, None, 'hello']"

parent_conn.send("吃饭没!")

p.join()

The two connection objects returned by Pipe() represent the two ends of the pipe. Each connection object has send() and recv() methods (among others). Note that data in a pipe may become corrupted if two processes (or threads) try to read from or write to the same end of the pipe at the same time. Of course there is no risk of corruption from processes using different ends of the pipe at the same time.

Managers

Queue和pipe只是实现了数据交互,并没实现数据共享,即一个进程去更改另一个进程的数据。

A manager object returned by Manager() controls a server process which holds Python objects and allows other processes to manipulate them using proxies.

from multiprocessing import Process, Managerdef f(d, l,n):

d[n] = '1'

d['2'] = 2

d[0.25] = None

l.append(n)    #print(l)

print("son process:",id(d),id(l))if __name__ == '__main__':

with Manager() as manager:

d = manager.dict()

l = manager.list(range(5))        print("main process:",id(d),id(l))

p_list = []        for i in range(10):

p = Process(target=f, args=(d,l,i))

p.start()

p_list.append(p)        for res in p_list:

res.join()        print(d)        print(l)

4.进程同步

Without using the lock output from the different processes is liable to get all mixed up.

from multiprocessing import Process, Lockdef f(l, i):

with l.acquire():        print('hello world %s'%i)if __name__ == '__main__':

lock = Lock()    for num in range(10):

Process(target=f, args=(lock, num)).start()

5.进程池

进程池内部维护一个进程序列,当使用时,则去进程池中获取一个进程,如果进程池序列中没有可供使用的进进程,那么程序就会等待,直到进程池中有可用进程为止。

进程池中有两个方法:apply

apply_async

from  multiprocessing import Process,Poolimport time,osdef Foo(i):

time.sleep(1)    print(i)    return i+100def Bar(arg):    print(os.getpid())    print(os.getppid())    print('logger:',arg)

pool = Pool(5)

Bar(1)print("----------------")for i in range(10):    #pool.apply(func=Foo, args=(i,))

#pool.apply_async(func=Foo, args=(i,))

pool.apply_async(func=Foo, args=(i,),callback=Bar)

pool.close()

pool.join()print('end')

四、协程

协程,又称微线程,纤程。英文名Coroutine。

优点1: 协程极高的执行效率。因为子程序切换不是线程切换,而是由程序自身控制,因此,没有线程切换的开销,和多线程比,线程数量越多,协程的性能优势就越明显。

优点2: 不需要多线程的锁机制,因为只有一个线程,也不存在同时写变量冲突,在协程中控制共享资源不加锁,只需要判断状态就好了,所以执行效率比多线程高很多。

因为协程是一个线程执行,那怎么利用多核CPU呢?最简单的方法是多进程+协程,既充分利用多核,又充分发挥协程的高效率,可获得极高的性能。

yield的简单实现

import timeimport queuedef consumer(name):    print("--->ready to eat baozi...")    while True:

new_baozi = yield

print("[%s] is eating baozi %s" % (name,new_baozi))        #time.sleep(1)def producer():

r = con.__next__()

r = con2.__next__()

n = 0    while 1:

time.sleep(1)        print("\033[32;1m[producer]\033[0m is making baozi %s and %s" %(n,n+1) )

con.send(n)

con2.send(n+1)

n +=2if __name__ == '__main__':

con = consumer("c1")

con2 = consumer("c2")

p = producer()

Greenlet

greenlet是一个用C实现的协程模块,相比与python自带的yield,它可以使你在任意函数之间随意切换,而不需把这个函数先声明为generator

from greenlet import greenlet

def test1():    print(12)

gr2.switch()    print(34)

gr2.switch()

def test2():    print(56)

gr1.switch()    print(78)

gr1 = greenlet(test1)

gr2 = greenlet(test2)

gr1.switch()

Gevent

import geventimport requests,time

start=time.time()def f(url):    print('GET: %s' % url)

resp =requests.get(url)

data = resp.text    print('%d bytes received from %s.' % (len(data), url))

gevent.joinall([

gevent.spawn(f, 'https://www.python.org/'),

gevent.spawn(f, 'https://www.yahoo.com/'),

gevent.spawn(f, 'https://www.baidu.com/'),

gevent.spawn(f, 'https://www.sina.com.cn/'),

])# f('https://www.python.org/')#

# f('https://www.yahoo.com/')#

# f('https://baidu.com/')#

# f('https://www.sina.com.cn/')print("cost time:",time.time()-start)

python apply_async死锁_python之并发编程(线程\进程\协程)相关推荐

  1. python协程和线程_python之并发编程(线程\进程\协程)

    一.进程和线程 1.进程 假如有两个程序A和B,程序A在执行到一半的过程中,需要读取大量的数据输入(I/O操作),而此时CPU只能静静地等待任务A读取完数据才能继续执行,这样就白白浪费了CPU资源.是 ...

  2. python线程进程协程面试_Python学习经验之谈:关于协程的理解和其相关面试问题...

    都知道Python非常适合初学者学习来入门编程,昨天有伙伴留言说面试了Python岗位,问及了一个关于协程的问题,想了想还是跟大家出一篇协程相关的文章和在Python面试中可能会问及的相关面试问题.都 ...

  3. 打开线程 | 进程 | 协程的大门

    不知从几何起,可能是大三那年的操作系统考试,也可能是刚经历完的秋招,这些概念总是迷迷糊糊,可能自己回答的和其他人的答复也差不多,并没有什么亮点,通常都会以:「我们换个题」的方式结束,有时候也挺尴尬的. ...

  4. 十四丶并发编程(线程 进程 协程)

    Yuan先生 知识预览 操作系统 回到顶部 操作系统 一 为什么要有操作系统? 现代计算机系统是由一个或者多个处理器,主存,磁盘,打印机,键盘,鼠标显示器,网络接口以及各种其他输入输出设备组成的复杂系 ...

  5. python_21_线程+进程+协程

    python_线程_进程_协程 什么是线程? -- os能够进行运算调度的最小单位,被包含在进程之中,是一串指令的集合 -- 每个线程都是独立的,可以访问同一进程下所有的资源 什么是进程? -- 每个 ...

  6. python 进程池阻塞和非阻塞_python 之 并发编程(进程池与线程池、同步异步阻塞非阻塞、线程queue)...

    9.11 进程池与线程池 池子使用来限制并发的任务数目,限制我们的计算机在一个自己可承受的范围内去并发地执行任务 池子内什么时候装进程:并发的任务属于计算密集型池子内什么时候装线程:并发的任务属于IO ...

  7. python 线程同步_Python并发编程-线程同步(线程安全)

    Python并发编程-线程同步(线程安全) 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 线程同步,线程间协调,通过某种技术,让一个线程访问某些数据时,其它线程不能访问这些数据,直 ...

  8. python多线程调度_python并发编程之进程、线程、协程的调度原理(六)

    进程.线程和协程的调度和运行原理总结. 系列文章 进程.线程的调度策略介绍 linux中的进程主要有三种调度策略: 优先级调度:将进程分为普通进程和实时进程: 先进先出(队列)调度:实时进程先创建的先 ...

  9. python并发编程之semaphore(信号量)_python 之 并发编程(守护进程、互斥锁、IPC通信机制)...

    9.5 守护进程 主进程创建守护进程 其一:守护进程会在主进程代码执行结束后就立即终止 其二:守护进程内无法再开启子进程,否则抛出异常:AssertionError: daemonic process ...

最新文章

  1. C++ 随机数生成的2种方法--生成指定范围内的随机数
  2. [.Net线程处理系列]专题二:线程池中的工作者线程
  3. 如何从网页上下载Flash?
  4. java多模块maven_Maven和Java多版本模块
  5. 第二阶段团队项目冲刺第三天
  6. Java:comp/env/讲解与JNDI
  7. Maven学习(三)————Maven核心概念(二)
  8. 客户端远程连接Oracle数据库
  9. 消息中间件 rabbitMQ
  10. 【Oracle学习笔记】
  11. Firefox上打开的标签页太多怎么办?
  12. FineReport10.0功能说明
  13. 模式识别与机器学习 第一章 绪论
  14. dxp全称_Protel DXP 2004 分立元件库元件名称中英对照表
  15. Dnsmasq+ipset+iptables基于域名的流量管理
  16. android hwcomposer
  17. 统信软件宣布旗下深度社区全新规划 打造我国主导的全球桌面系统根社区
  18. 数字证书X509格式标准简介
  19. python画玫瑰图_三步学会用python画一个简单的玫瑰图
  20. SAP 教程之 03 如何为 Inbound IDOC 配置 SAP,配置合作伙伴配置文件

热门文章

  1. 计算机网络教学方法,信息类专业计算机网络教学方法探讨
  2. java基于springboot+vue的企业员工工资考勤系统 nodejs前后端分离
  3. Ubuntu 16.04 LTS 安装RealSense R200 驱动以及SDK配置+QT+OpenCV
  4. linux redis简单操作
  5. 更优雅的编写JavaScript,使用这些函数秒变大神
  6. oracle --sql--转换表字段日期格式(年月日时分秒转换年月日)
  7. 128階數的Shunt音量控制器
  8. 420集的python教程下载_微软官方发布了最新420集Python教程,这教程简直就是编程界福利...
  9. windows server 2012 r2打造工作站链接 和 RTSS画面防止撕裂方法(包括笔记本独显撕裂,视频撕裂等)...
  10. 通信专业 英语词汇大全(持续更新)