精华内容
下载资源
问答
  • Python 并发

    千次阅读 2019-04-22 21:34:09
    Python 并发 Python 1. 多进程 Unix/Linux操作系统提供了一个fork()系统调用,它非常特殊。普通的函数调用,调用一次,返回一次,但是fork()调用一次,返回两次,因为操作系统自动把当前进程(称为父进程)复制...
    
     

    Python 并发

    Python

    1. 多进程

    Unix/Linux操作系统提供了一个fork()系统调用,它非常特殊。普通的函数调用,调用一次,返回一次,但是fork()调用一次,返回两次,因为操作系统自动把当前进程(称为父进程)复制了一份(称为子进程),然后,分别在父进程和子进程内返回。

    子进程永远返回0,而父进程返回子进程的ID。这样做的理由是,一个父进程可以fork出很多子进程,所以,父进程要记下每个子进程的ID,而子进程只需要调用getppid()就可以拿到父进程的ID。

    Python的multiprocessing模块提供了一个Process类来代表一个进程对象

    开启进程:

    from multiprocessing import Process
    import os
    ​
    # 子进程要执行的代码
    def run_proc(name):
      print('Run child process %s (%s)...' % (name, os.getpid()))
    ​
    if __name__=='__main__':
      print('Parent process %s.' % os.getpid())
      p = Process(target=run_proc, args=('test',))
      print('Child process will start.')
      p.start()
      p.join()
      print('Child process end.')

    join()方法可以等待子进程结束后再继续往下运行,通常用于进程间的同步。

    进程池:

    如果要启动大量的子进程,可以用进程池的方式批量创建子进程

    p = Pool(4)
    for i in range(5):
      p.apply_async(long_time_task, args=(i,))
    print('Waiting for all subprocesses done...')
    p.close()
    p.join()

    进程间通信:

    Process之间肯定是需要通信的,操作系统提供了很多机制来实现进程间的通信。Python的multiprocessing模块包装了底层的机制,提供了QueuePipes等多种方式来交换数据。

    q = Queue()
    q.put(value)
    value = q.get(True)
    ​
    pipe_main = Pipe(False)
    pipe_main[1].send(best_plan_t)
    best_gene = pipe_main[0].recv()

    2. 多线程

    调用:

    Python的标准库提供了两个模块:_threadthreading_thread是低级模块,threading是高级模块,对_thread进行了封装。绝大多数情况下,我们只需要使用threading这个高级模块。

    启动一个线程就是把一个函数传入并创建Thread实例,然后调用start()开始执行:

    import time, threading
    ​
    # 新线程执行的代码:
    def loop():
      print('thread %s is running...' % threading.current_thread().name)
      n = 0
      while n < 5:
          n = n + 1
          print('thread %s >>> %s' % (threading.current_thread().name, n))
          time.sleep(1)
      print('thread %s ended.' % threading.current_thread().name)
    ​
    print('thread %s is running...' % threading.current_thread().name)
    t = threading.Thread(target=loop, name='LoopThread')
    t.start()
    t.join()
    print('thread %s ended.' % threading.current_thread().name)

    Lock

    多线程和多进程最大的不同在于,多进程中,同一个变量,各自有一份拷贝存在于每个进程中,互不影响,而多线程中,所有变量都由所有线程共享,所以,任何一个变量都可以被任何一个线程修改,因此,线程之间共享数据最大的危险在于多个线程同时改一个变量,把内容给改乱了。

    创建一个锁就是通过threading.Lock()来实现线程间同步

    获得锁的线程用完后一定要释放锁,否则那些苦苦等待锁的线程将永远等待下去,成为死线程。所以我们用try...finally来确保锁一定会被释放。

    锁的好处就是确保了某段关键代码只能由一个线程从头到尾完整地执行,坏处当然也很多,首先是阻止了多线程并发执行,包含锁的某段代码实际上只能以单线程模式执行,效率就大大地下降了。其次,由于可以存在多个锁,不同的线程持有不同的锁,并试图获取对方持有的锁时,可能会造成死锁,导致多个线程全部挂起,既不能执行,也无法结束,只能靠操作系统强制终止。

    因为Python的线程虽然是真正的线程,但解释器执行代码时,有一个GIL锁:Global Interpreter Lock,任何Python线程执行前,必须先获得GIL锁,然后,每执行100条字节码,解释器就自动释放GIL锁,让别的线程有机会执行。这个GIL全局锁实际上把所有线程的执行代码都给上了锁,所以,多线程在Python中只能交替执行,即使100个线程跑在100核CPU上,也只能用到1个核。

    ThreadLocal:

    ThreadLocal解决了参数在一个线程中各个函数之间互相传递的问题。

    全局变量local_school就是一个ThreadLocal对象,每个Thread对它都可以读写student属性,但互不影响。你可以把local_school看成全局变量,但每个属性如local_school.student都是线程的局部变量,可以任意读写而互不干扰,也不用管理锁的问题,ThreadLocal内部会处理。

    import threading
    ​
    # 创建全局ThreadLocal对象:
    local_school = threading.local()
    ​
    def process_student():
      # 获取当前线程关联的student:
      std = local_school.student
      print('Hello, %s (in %s)' % (std, threading.current_thread().name))
    ​
    def process_thread(name):
      # 绑定ThreadLocal的student:
      local_school.student = name
      process_student()
    ​
    t1 = threading.Thread(target= process_thread, args=('Alice',), name='Thread-A')
    t2 = threading.Thread(target= process_thread, args=('Bob',), name='Thread-B')
    t1.start()
    t2.start()
    t1.join()
    t2.join()

     

    3. 协程

    Coroutine,又叫协程,是轻量级线程,拥有自己的寄存器上下文和栈。协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈。

    协程的应用场景:I/O 密集型任务。这一点与多线程有些类似,但协程调用是在一个线程内进行的,是单线程,切换的开销小,因此效率上略高于多线程。而且协程不需要锁,而线程需要锁来进行数据同步。协程是编译器级的,Process和Thread是操作系统级的。

    Process和Thread是os通过调度算法,保存当前的上下文,然后从上次暂停的地方再次开始计算,重新开始的地方不可预期,每次CPU计算的指令数量和代码跑过的CPU时间是相关的,跑到os分配的cpu时间到达后就会被os强制挂起。Coroutine是编译器的魔术,通过插入相关的代码使得代码段能够实现分段式的执行,重新开始的地方是yield关键字指定的,一次一定会跑到一个yield对应的地方。

    来看例子:

    传统的生产者-消费者模型是一个线程写消息,一个线程取消息,通过锁机制控制队列和等待,但一不小心就可能死锁。

    如果改用协程,生产者生产消息后,直接通过yield跳转到消费者开始执行,待消费者执行完毕后,切换回生产者继续生产,效率极高:

    def consumer():
      r = ''
      while True:
          n = yield r
          if not n:
              return
          print('[CONSUMER] Consuming %s...' % n)
          r = '200 OK'
    ​
    def produce(c):
      c.send(None)
      n = 0
      while n < 5:
          n = n + 1
          print('[PRODUCER] Producing %s...' % n)
          r = c.send(n)
          print('[PRODUCER] Consumer return: %s' % r)
      c.close()
    ​
    c = consumer()
    produce(c)

    执行结果:

    [PRODUCER] Producing 1...
    [CONSUMER] Consuming 1...
    [PRODUCER] Consumer return: 200 OK
    [PRODUCER] Producing 2...
    [CONSUMER] Consuming 2...
    [PRODUCER] Consumer return: 200 OK
    [PRODUCER] Producing 3...
    [CONSUMER] Consuming 3...
    [PRODUCER] Consumer return: 200 OK
    [PRODUCER] Producing 4...
    [CONSUMER] Consuming 4...
    [PRODUCER] Consumer return: 200 OK
    [PRODUCER] Producing 5...
    [CONSUMER] Consuming 5...
    [PRODUCER] Consumer return: 200 OK

    注意到consumer函数是一个generator,把一个consumer传入produce后:

    1. 首先调用c.send(None)启动生成器;

    2. 然后,一旦生产了东西,通过c.send(n)切换到consumer执行;

    3. consumer通过yield拿到消息,处理,又通过yield把结果传回;

    4. produce拿到consumer处理的结果,继续生产下一条消息;

    5. produce决定不生产了,通过c.close()关闭consumer,整个过程结束。

    整个流程无锁,由一个线程执行,produceconsumer协作完成任务,所以称为“协程”,而非线程的抢占式多任务。

    最后套用Donald Knuth的一句话总结协程的特点:

    “子程序就是协程的一种特例。”

     

    asyncio

    asyncio是Python 3.4版本引入的标准库,直接内置了对异步IO的支持。

    asyncio的编程模型就是一个消息循环。我们从asyncio模块中直接获取一个EventLoop的引用,然后把需要执行的协程扔到EventLoop中执行,就实现了异步IO。

    asyncio实现Hello world代码如下:

    import asyncio
    ​
    @asyncio.coroutine
    def hello():
      print("Hello world!")
      # 异步调用asyncio.sleep(1):
      r = yield from asyncio.sleep(1)
      print("Hello again!")
    ​
    # 获取EventLoop:
    loop = asyncio.get_event_loop()
    # 执行coroutine
    loop.run_until_complete(hello())
    loop.close()

    @asyncio.coroutine把一个generator标记为coroutine类型,然后,我们就把这个coroutine扔到EventLoop中执行。

    hello()会首先打印出Hello world!,然后,yield from语法可以让我们方便地调用另一个generator。由于asyncio.sleep()也是一个coroutine,所以线程不会等待asyncio.sleep(),而是直接中断并执行下一个消息循环。当asyncio.sleep()返回时,线程就可以从yield from拿到返回值(此处是None),然后接着执行下一行语句。

    asyncio.sleep(1)看成是一个耗时1秒的IO操作,在此期间,主线程并未等待,而是去执行EventLoop中其他可以执行的coroutine了,因此可以实现并发执行。

    我们用Task封装两个coroutine试试:

    import threading
    import asyncio
    ​
    @asyncio.coroutine
    def hello():
      print('Hello world! (%s)' % threading.currentThread())
      yield from asyncio.sleep(1)
      print('Hello again! (%s)' % threading.currentThread())
    ​
    loop = asyncio.get_event_loop()
    tasks = [hello(), hello()]
    loop.run_until_complete(asyncio.wait(tasks))
    loop.close()

    观察执行过程:

    Hello world! (<_MainThread(MainThread, started 140735195337472)>)
    Hello world! (<_MainThread(MainThread, started 140735195337472)>)
    (暂停约1秒)
    Hello again! (<_MainThread(MainThread, started 140735195337472)>)
    Hello again! (<_MainThread(MainThread, started 140735195337472)>)

    由打印的当前线程名称可以看出,两个coroutine是由同一个线程并发执行的。

    如果把asyncio.sleep()换成真正的IO操作,则多个coroutine就可以由一个线程并发执行。

    我们用asyncio的异步网络连接来获取sina、sohu和163的网站首页:

    import asyncio
    ​
    @asyncio.coroutine
    def wget(host):
      print('wget %s...' % host)
      connect = asyncio.open_connection(host, 80)
      reader, writer = yield from connect
      header = 'GET / HTTP/1.0\r\nHost: %s\r\n\r\n' % host
      writer.write(header.encode('utf-8'))
      yield from writer.drain()
      while True:
          line = yield from reader.readline()
          if line == b'\r\n':
              break
          print('%s header > %s' % (host, line.decode('utf-8').rstrip()))
      # Ignore the body, close the socket
      writer.close()
    ​
    loop = asyncio.get_event_loop()
    tasks = [wget(host) for host in ['www.sina.com.cn', 'www.sohu.com', 'www.163.com']]
    loop.run_until_complete(asyncio.wait(tasks))
    loop.close()

    执行结果如下:

    wget www.sohu.com...
    wget www.sina.com.cn...
    wget www.163.com...
    (等待一段时间)
    (打印出sohu的header)
    www.sohu.com header > HTTP/1.1 200 OK
    www.sohu.com header > Content-Type: text/html
    ...
    (打印出sina的header)
    www.sina.com.cn header > HTTP/1.1 200 OK
    www.sina.com.cn header > Date: Wed, 20 May 2015 04:56:33 GMT
    ...
    (打印出163的header)
    www.163.com header > HTTP/1.0 302 Moved Temporarily
    www.163.com header > Server: Cdn Cache Server V2.0
    ...

    可见3个连接由一个线程通过coroutine并发完成。

     

    asyncio提供了完善的异步IO支持;

    异步操作需要在coroutine中通过yield from完成;

    多个coroutine可以封装成一组Task然后并发执行。

     

    async/await

    asyncio提供的@asyncio.coroutine可以把一个generator标记为coroutine类型,然后在coroutine内部用yield from调用另一个coroutine实现异步操作。

    为了简化并更好地标识异步IO,从Python 3.5开始引入了新的语法asyncawait,可以让coroutine的代码更简洁易读。

    请注意,asyncawait是针对coroutine的新语法,要使用新的语法,只需要做两步简单的替换:

    1. @asyncio.coroutine替换为async

    2. yield from替换为await

    让我们对比一下上一节的代码:

    @asyncio.coroutine
    def hello():
      print("Hello world!")
      r = yield from asyncio.sleep(1)
      print("Hello again!")

    用新语法重新编写如下:

    async def hello():
      print("Hello world!")
      r = await asyncio.sleep(1)
      print("Hello again!")

    剩下的代码保持不变。

     

     

    参考:

    https://www.liaoxuefeng.com 廖雪峰Python教程

    展开全文
  • python并发

    2021-03-18 16:49:39
    并发 CPU密集型、IO密集型 CPU密集型/计算密集型:在执行过程中大部分时间用来做计算,I/O设备访问次数少,CPU占用率高。 I/O密集性:在执行过程中大部分时间在等I/O的读/写操作。 总结: CPU密集型—增加CPU的核心...

    并发

    CPU密集型、IO密集型

    CPU密集型/计算密集型:在执行过程中大部分时间用来做计算,I/O设备访问次数少,CPU占用率高。
    I/O密集性:在执行过程中大部分时间在等I/O的读/写操作。


    总结:
    CPU密集型—增加CPU的核心数,减少线程,c语言
    I/O密集型—增加线程,脚本语言

    Python多线程----I/O密集型

    在Python多线程下,每个线程的执行方式:
    1.获取GIL(全局解释器锁)
    2.执行代码直到sleep或者是python虚拟机将其挂起。
    3.释放GIL
    所以Python中的多线程并不是并行执行,而是“交替执行”。

    展开全文
  • Python并发

    2018-08-17 13:53:00
    最新Python异步编程详解:https://www.jianshu.com/p/b036e6e97c18 Python之禅 完全理解Python迭代对象、迭代器、生成器:...使用Python进行并发编程:http://python.jobbole.com/81255/ Pyt...

    最新Python异步编程详解:https://www.jianshu.com/p/b036e6e97c18

    Python之禅

    完全理解Python迭代对象、迭代器、生成器:https://foofish.net/iterators-vs-generators.html

    使用Python进行并发编程:http://python.jobbole.com/81255/

     

    Python通过future处理并发

    python之concurrent.futures模块

    python协程面试题(一):https://blog.csdn.net/leon_wzm/article/details/79085235

    python异步爬虫: https://blog.csdn.net/whuhan2013/article/details/52529477

    转载于:https://www.cnblogs.com/charlieLeo/p/9492911.html

    展开全文
  • Python并发管理

    2018-02-07 20:55:48
    Python并发管理视频培训教程,该课程主要分享Python并发方面的知识,包括线程、协程、进程三大模块,每个模块都会进行详细讲解,包括线程的创建、总结、线程内死锁、堆栈、协程的引入、迭代器、协程原理、队列、进程...
  • python 并发编程

    2019-10-02 19:50:54
    理解Python并发编程一篇就够了 - 线程篇理解Python并发编程一篇就够了 - 进程篇使用Python进行并发编程-PoolExecutor篇使用Python进行并发编程-我为什么不喜欢Gevent使用Python进行并发编程-asyncio篇(一)使用Python...

    以下链接均来自网络

    『Python并发编程』

    理解Python并发编程一篇就够了 - 线程篇
    理解Python并发编程一篇就够了 - 进程篇
    使用Python进行并发编程-PoolExecutor篇
    使用Python进行并发编程-我为什么不喜欢Gevent
    使用Python进行并发编程-asyncio篇(一)
    使用Python进行并发编程-asyncio篇(二)
    使用Python进行并发编程-asyncio篇(三)

    python异步多线程超高性能爬虫爬取又拍云图片

     

    Python3.5协程学习研究

    使用asyncio+aiohttp实现的链家异步爬虫

    转载于:https://www.cnblogs.com/c-x-a/p/9076661.html

    展开全文
  • Python并发编程GPU

    2018-09-21 23:23:54
    还压缩包里面包含了Python并发编程PDF文档与配套代码Code,适合当今深度学习GPU并发分布式计算,欢迎大家下载学习。
  • 本篇文章主要介绍了python并发2之使用asyncio处理并发,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
  • PYTHON并发编程(三)

    2019-07-19 10:39:49
    从0基础开始讲解PYTHON并发编程。重磅推出,必是精品,不容错过。
  • PYTHON并发编程(二)

    2019-07-19 10:37:14
    从0基础开始讲解PYTHON并发编程。重磅推出,必是精品,不容错过。
  • PYTHON并发编程(一)

    2019-07-12 15:39:40
    从0基础开始讲解PYTHON并发编程。重磅推出,必是精品,不容错过。
  • 主要介绍了python 并发下载器实现方法,结合实例形式详细分析了并发下载器相关原理及Python并发下载视频的相关操作技巧,需要的朋友可以参考下
  • python 并发编程 协程 协程介绍 python 并发编程 协程 greenlet模块 python 并发编程 协程 gevent模块 python 并发编程 基于gevent模块实现并发的套接字通信 python 并发编程 协程池 python 并发编程 基于...
  • 主要为大家详细介绍了python并发和异步编程实例,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
  • 学会使用python完成一程序设计. 初步形成编程思维. 学会使用函数对程序进行更加规范化的处理. 从0基础开始讲解PYTHON并发编程。重磅推出,必是精品,不容错过。
  • Python并发目录

    2018-04-01 00:17:00
    Python并发目录 Python-socket网络编程 Python网络编程-IO阻塞与非阻塞及多路复用 Python进程-理论 Python进程-实现 Python进程间通信 Python进程池 Python线程 Python协程 注意点 python编程中的if __...
  • 主要介绍了python并发编程之线程实例解析,具有一定借鉴价值,需要的朋友可以参考下
  • 15、python并发编程

    千次阅读 2021-02-18 23:30:10
    15、python并发编程 多道技术 进程理论 开启进程的两种方式 进程对象的join方法 进程之间数据相互隔离 进程对象的其他方法 僵尸进程与孤儿进程 守护进程与互斥锁 进程通信IPC机制 生产者消费模型 一、多道技术 多...
  • python 并发编程 IO模型介绍 python 并发编程 socket 服务端 客户端 阻塞io行为 python 并发编程 阻塞IO模型 python 并发编程 非阻塞IO模型 python 并发编程 多路复用IO模型 python 并发编程 异步IO模型 转载于...
  • Python并发编程 背景知识 python并发编程--多进程1 python并发编程--多进程2 python并发编程--多线程1 python并发编程--多线程2 python并发编程--协程 python并发编程--IO模型 ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 16,751
精华内容 6,700
关键字:

python并发

python 订阅