python 协程

线程Routine

线程是CPU进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一个进程中可以并发多个线程,每条线程执行不同的任务。对于抢占式操作系统来说,当线程数越多时,CPU发生上下文切换的概率就越大,从而导致CPU占用很高,但是系统效率却上不去的问题。

多线程python实现

1.直接调用

import threading
import time

def print_time( threadName, delay):
   count = 0
   while count < 3:
      time.sleep(delay)
      count += 1
      print("%s: %s" % ( threadName, time.ctime(time.time())))

if __name__ == "__main__":
    t1=threading.Thread(target=print_time,args=("thread 1",3)) #生成线程实例
    t2=threading.Thread(target=print_time,args=("thread 2",1))

    t1.setName("aaa")   #设置线程名
    t1.start()  #启动线程
    t2.start()
    t2.join()   #join  等待t2先执行完
    print("end")
    print(t1.getName()) #获取线程名
'''
结果:
thread 2: Sat Oct 19 05:00:21 2019
thread 2: Sat Oct 19 05:00:22 2019
thread 1: Sat Oct 19 05:00:23 2019
thread 2: Sat Oct 19 05:00:23 2019
end
aaa
thread 1: Sat Oct 19 05:00:26 2019
thread 1: Sat Oct 19 05:00:29 2019
'''

2.继承式调用,重写init方法和run方法

import threading
import time

class MyThread(threading.Thread):
    def __init__(self,name,delay):
        threading.Thread.__init__(self)
        self.name = name
        self.delay = delay
    def run(self):
        print_time(self.name,self.delay)
        print("print one")
        time.sleep(3)

def print_time( threadName, delay):
   count = 0
   while count < 3:
      time.sleep(delay)
      count += 1
      print("%s: %s" % ( threadName, time.ctime(time.time())))

if __name__ == "__main__":
    t1=MyThread("thread 1",1)
    t2=MyThread("thread 2",2)
    t1.start()
    t2.start()
'''
结果:
thread 1: Sat Oct 19 05:15:40 2019
thread 2: Sat Oct 19 05:15:41 2019
thread 1: Sat Oct 19 05:15:41 2019
thread 1: Sat Oct 19 05:15:42 2019
print one
thread 2: Sat Oct 19 05:15:43 2019
thread 2: Sat Oct 19 05:15:45 2019
print one
'''

3.线程加锁

import threading
import time

num = 100 #设置一个共享变量
lock=threading.Lock()  #生成全局锁
def show():
    global num  #在函数内操作函数外变量,需设置为全局变量
    time.sleep(1)
    lock.acquire()  #修改前加锁
    num -= 1
    lock.release()  #修改后解锁
list=[]
for i in range(100):
    t = threading.Thread(target=show)
    t.start()
    list.append(t)

for t in list:
    t.join()

print(num)     #结果 0

4.Semaphore
同时允许一定数量的线程更改数据

import threading 
import time 

def run(n):
    semaphore.acquire()
    time.sleep(1) 
    print("run the thread: %s" %n)
    semaphore.release() 
if __name__ == '__main__':
    semaphore = threading.BoundedSemaphore(3) #设置最多允许3个线程同时运行
    for i in range(20):
        t = threading.Thread(target=run,args=(i,))
        t.start() 
while threading.active_count() != 1: 
    pass
else: 
    print('----done---')

5.event
实现两个或多个线程间的交互,提供了三个方法 set、wait、clear,默认碰到event.wait 方法时就会阻塞。
  event.set(),设定后遇到wait不阻塞
  event.clear(),设定后遇到wait后阻塞
  event.isSet(),判断有没有被设定

import threading 
def start(): 
    print("---start---1")
    event.wait() #阻塞
    print("---start---2") 
if __name__ == "__main__":
    event = threading.Event()
    t = threading.Thread(target=start)
    t.start()
    result=input(">>:") 
    if result == "set":
        event.set() #设定set,wait不阻塞
'''
结果:
---start---1

>>:set
---start---2
'''

协程Coroutine

又称微线程,是用户模式下的轻量级线程,它是程序语言利用逻辑在线程中创建的可以互相中断执行的代码段(个人理解),比如在执行函数A时,可以随时中断,去执行函数B,然后中断继续执行函数A(可以自由切换)。但这一过程靠程序控制,但并不是函数调用(没有调用语句),这整个过程看似像多线程,然而协程只有一个线程执行。因此对比多线程,没有线程切换的开销,所以执行效率极高。

  1. yield协程
import time

def consumer():
    r = 'start'
    while True:
        n = yield r
        if not n:
            print("n is empty")
            continue
        print("消费了 %s" % n)
        r = "ok"

def producer(c):
    # 启动generator
    start_value = c.send(None)
    print(start_value)
    n = 0
    while n < 3:
        n += 1
        print("生产了 %d" % n)
        r = c.send(n)
        print(r)
    c.close()  # 关闭generator

c = consumer()  # 创建生成器
producer(c)  # 传入generator
'''
结果:
start
生产了 1
消费了 1
ok
生产了 2
消费了 2
ok
生产了 3
消费了 3
ok
'''
  1. greenlet协程,直接将函数包装成协程,需手动切换
from greenlet import greenlet
import random
import time

def producer():
    while True:
        item=random.randint(0,99)
        print("生产了 %s" %item)
        c.switch(item)  # 切换到消费者,并将item传入消费者
        time.sleep(1)
        
def consumer():
    while True:
        item=p.switch()   # 切换到消费者,并等待消费者传入item
        print("消费了 %s" %item)
        
c=greenlet(consumer)  # 将一个普通函数变成协程
p=greenlet(producer)
c.switch()  # 让消费者先进入暂停状态(只有恢复时才能接收数据)
'''
结果:
生产了 1
消费了 1
生产了 69
消费了 69
生产了 75
消费了 75
'''
  1. gevent协程,只在遇到阻塞时切换到另一个协程继续执行
from gevent import monkey
import gevent
from gevent.queue import Queue
import random
import time

queue=Queue(3)

def producer(queue):
    while True:
        item=random.randint(0,99)
        print("生产了 %s" %item)
        queue.put(item)
        # c.switch(item)  # 切换到消费者,并将item传入消费者
        time.sleep(1)
        
def consumer(queue):
    while True:
        item=queue.get()
        #item=p.switch()   # 切换到消费者,并等待消费者传入item
        print("消费了 %s" %item)
        
c=gevent.spawn(consumer,queue)  # 将函数封装成协程,并开始调度
p=gevent.spawn(producer,queue)

gevent.joinall([p,c])  # 阻塞(一阻塞就切换协程)等待

'''
结果:
生产了 29
生产了 52
生产了 14
生产了 45
消费了 29
消费了 52
消费了 14
生产了 17
生产了 61
生产了 41
消费了 45
消费了 17
消费了 61
'''
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,539评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,594评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,871评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,963评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,984评论 6 393
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,763评论 1 307
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,468评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,357评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,850评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,002评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,144评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,823评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,483评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,026评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,150评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,415评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,092评论 2 355

推荐阅读更多精彩内容