zoukankan      html  css  js  c++  java
  • python 之 并发编程(线程Event、协程)

    9.14 线程Event

    connect线程执行到event.wait()时开始等待,直到check线程执行event.set()后立即继续线程connect

    from threading import Event,current_thread,Thread
    import time
    event=Event()
    def check():
        print('%s 正在检测服务是否正常....' %current_thread().name)
        time.sleep(3)
        event.set()
    ​
    def connect():
        print('%s 等待连接...' %current_thread().name)
        event.wait()
        print('%s 开始连接...' % current_thread().name)
    ​
    if __name__ == '__main__':
        t1=Thread(target=connect)
        t2=Thread(target=connect)
        t3=Thread(target=connect)
    ​
        c1=Thread(target=check)
    ​
        t1.start()
        t2.start()
        t3.start()
        c1.start()

    connect线程执行到event.wait(1)时开始等待1秒,count计数+1,如果到check线程执行event.set()前已经4秒,则终止线程connect,否则event.is_set() is True ,立即继续线程connect

    from threading import Event,current_thread,Thread
    import time
    event=Event()
    def check():
        print('%s 正在检测服务是否正常....' %current_thread().name)
        time.sleep(5)
        event.set()
    ​
    def connect():
        count=1
        while not event.is_set():   #event是否被set过,是返回True,否返回False
            if count ==  4:
                print('尝试的次数过多,请稍后重试')
                return
            print('%s 尝试第%s次连接...' %(current_thread().name,count))
            event.wait(1)
            count+=1
        print('%s 开始连接...' % current_thread().name)
    ​
    if __name__ == '__main__':
        t1=Thread(target=connect)
        t2=Thread(target=connect)
        t3=Thread(target=connect)
    ​
        c1=Thread(target=check)
    ​
        t1.start()
        t2.start()
        t3.start()
        c1.start()
    View Code

    9.15 协程

    协程:是单线程下的并发,又称微线程,纤程。一句话说明什么是线程:协程是一种用户态的轻量级线程,即协程是由用户程序自己控制调度的。

    1. python的线程属于内核级别的,即由操作系统控制调度(如单线程遇到i/o或执行时间过长就会被迫交出cpu执行权限,切换其他线程运行)

    2. 单线程内开启协程,一旦遇到i/o,就会从应用程序级别(而非操作系统)控制切换到其他任务,以此来提升效率(非i/o操作的切换与效率无关)

    3. 对比操作系统控制线程的切换,用户在单线程内控制协程的切换

      优点:
    1. 协程的切换开销更小,属于程序级别的切换,操作系统完全感知不到,因而更加轻量级
    2. 单线程内就可以实现并发的效果,最大限度地利用cpu
       
    缺点:
    1. 协程的本质是单线程下,无法利用多核,可以是一个程序开启多个进程,每个进程内开启多个线程,每个线程内开启协程
    2. 协程指的是单个线程,因而一旦协程出现阻塞,将会阻塞整个线程

    9.151 greenlet模块

     from greenlet import greenlet
      import time
      
      def eat(name):
          print('%s eat 1' %name)
          #time.sleep(30)           遇到i/o不能自动切换
          g2.switch('alex')
          print('%s eat 2' %name)
          g2.switch()
      def play(name):
          print('%s play 1' %name)
          g1.switch()
          print('%s play 2' %name)
      
      g1=greenlet(eat)
      g2=greenlet(play)
      
      g1.switch('egon') # egon eat 1   alex play 1   egon eat 2   alex play 2

    9.152 gevent模块

    import gevent
    ​
    def eat(name):
        print('%s eat 1' %name)
        gevent.sleep(5)         #只检测gevent的i/o
        print('%s eat 2' %name)
    def play(name):
        print('%s play 1' %name)
        gevent.sleep(3)
        print('%s play 2' %name)
    ​
    g1=gevent.spawn(eat,'egon') #异步提交任务
    g2=gevent.spawn(play,'alex')
    ​
    # gevent.sleep(100)
    # g1.join()
    # g2.join()                # joinall等待任务执行完毕再结束线程
    gevent.joinall([g1,g2])     # egon eat 1     alex play 1    alex play 2   egon eat 2
    from gevent import monkey;monkey.patch_all()#标记所有(包括time等)的i/o
    import gevent
    import time
    ​
    def eat(name):
        print('%s eat 1' %name)
        time.sleep(5)            #time的i/o也可以检测
        print('%s eat 2' %name)
    def play(name):
        print('%s play 1' %name)
        time.sleep(3)
        print('%s play 2' %name)
    ​
    g1=gevent.spawn(eat,'egon')
    g2=gevent.spawn(play,'alex')
    ​
    # gevent.sleep(100)
    # g1.join()
    # g2.join()
    gevent.joinall([g1,g2])       # egon eat 1   alex play 1    alex play 2   egon eat 2

    验证协程的假名:

    from gevent import monkey;monkey.patch_all()#标记所有time等的i/o
    from threading import current_thread
    import gevent
    import time
    ​
    def eat():
        print('%s eat 1' %current_thread().name)
        time.sleep(5)
        print('%s eat 2' %current_thread().name)
    def play():
        print('%s play 1' %current_thread().name)
        time.sleep(3)
        print('%s play 2' %current_thread().name)
    ​
    g1=gevent.spawn(eat)
    g2=gevent.spawn(play)
    ​
    # gevent.sleep(100)
    # g1.join()
    # g2.join()
    print(current_thread().name)#MainThread
    gevent.joinall([g1,g2])     #DummyThread-1 eat 1     DummyThread-2 play 1  DummyThread-2 play 2                             DummyThread-1 eat 2
    View Code

    9.153 基于协程实现并发的套接字通信

    服务端:

    from gevent import monkey,spawn;monkey.patch_all()#标记所有time等的i/o
    from threading import Thread
    from socket import *def talk(conn):
        while True:
            try:
                data=conn.recv(1024)
                if not data:break
                conn.send(data.upper())
            except ConnectionResetError:
                break
        conn.close()
    ​
    def server(ip,port,backlog=5):
        s = socket()
        s.bind((ip,port))
        s.listen(backlog)
    ​
        while True:
            conn, addr = s.accept()
            print(addr)
          
            g=spawn(talk,conn)  # 通信
        s.close()
    ​
    if __name__ == '__main__':
        spawn(server,'127.0.0.1',8080).join()
        # server(('127.0.0.1',8080))
    View Code

    客户端:

    from threading import Thread,current_thread
    from socket import *
    import os
    ​
    def client():
        client = socket()
        client.connect(('127.0.0.1', 8080))
    ​
        while True:
            data = '%s hello' % current_thread().name
            client.send(data.encode('utf-8'))
            res = client.recv(1024)
            print(res.decode('utf-8'))
    ​
    if __name__ == '__main__':
        for i in range(1000):
            t=Thread(target=client)
            t.start()
    View Code
  • 相关阅读:
    国内代码托管平台(Git和SVN)
    搭建网络svn实战
    2016你一定要试试这8款原型设计工具
    Linux下查看用户列表
    详解Oracle DELETE和TRUNCATE 的区别
    Oracle 用户表空间查看、修改大小、设置自增长等
    win7电脑定时开机设置方法
    weblogic负载分发
    怎样实现一个数据库关系系统?
    选择数据库管理系统(DBMS)时主要考虑的因素
  • 原文地址:https://www.cnblogs.com/mylu/p/11253143.html
Copyright © 2011-2022 走看看