Python 中的多线程,多进程,并发,并行,同步,通信

本文简单介绍了Python中并发和并行的机理,如何实现并发和并,以及一些多线程,多进程之间通信和同步的问题

并发和并行

知乎上 龚昱阳 Dozer的说明的很形象,在此借用:
https://www.zhihu.com/question/33515481

你吃饭吃到一半,电话来了,你一直到吃完了以后才去接,这就说明你不支持并发也不支持并行。
你吃饭吃到一半,电话来了,你停了下来接了电话,接完后继续吃饭,这说明你支持并发。
你吃饭吃到一半,电话来了,你一边打电话一边吃饭,这说明你支持并行。

并发的关键是你有处理多个任务的能力,不一定要同时。
并行的关键是你有同时处理多个任务的能力。

所以我认为它们最关键的点就是:是否是『同时』。

Python 中没有真正的并行,只有并发

无论你的机器有多少个CPU, 同一时间只有一个Python解析器执行。这也和大部分解释型语言一致, 都不支持并行。这应该是python设计的先天缺陷。

javascript也是相同的道理, javascript早起的版本只支持单任务,后来通过worker来支持并发。

Python中的多线程

先复习一下进程和线程的概念

所谓进程,简单的说就是一段程序的动态执行过程,是系统进行资源分配和调度的一个基本单位。一个进程中又可以包含若干个独立的执行流,我们将这些执行流称为线程,线程是CPU调度和分配的基本单位。同一个进程的线程都有自己的专有寄存器,但内存等资源是共享的。

这里有一个更加形象的解释, 出自阮一峰大神的杰作:
http://www.ruanyifeng.com/blog/2013/04/processes_and_threads.html

Python中的thread的使用
  • 通过 thread.start_new_thread 方法

    import thread
    import time
    
    # Define a function for the thread
    def print_time( threadName, delay):
       count = 0
       while count < 5:
          time.sleep(delay)
          count += 1
          print "%s: %s" % ( threadName, time.ctime(time.time()) )
    
    # Create two threads as follows
    try:
       thread.start_new_thread( print_time, ("Thread-1", 2, ) )
       thread.start_new_thread( print_time, ("Thread-2", 4, ) )
    except:
       print "Error: unable to start thread"
    
    while 1:
       pass
    
  • 通过继承thread

    #!/usr/bin/python
    import threading
    import time
    exitFlag = 0
    class myThread (threading.Thread):
        def __init__(self, threadID, name, counter):
            threading.Thread.__init__(self)
            self.threadID = threadID
            self.name = name
            self.counter = counter
        def run(self):
            print "Starting " + self.name
            print_time(self.name, self.counter, 5)
            print "Exiting " + self.name
    
    def print_time(threadName, delay, counter):
        while counter:
            if exitFlag:
                threadName.exit()
            time.sleep(delay)
            print "%s: %s" % (threadName, time.ctime(time.time()))
            counter -= 1
    
    # Create new threads
    thread1 = myThread(1, "Thread-1", 1)
    thread2 = myThread(2, "Thread-2", 2)
    
    # Start new Threads
    thread1.start()
    thread2.start()
    print "Exiting Main Thread"
    
  • 线程的同步

    #!/usr/bin/python
    
    import threading
    import time
    
    class myThread (threading.Thread):
        def __init__(self, threadID, name, counter):
            threading.Thread.__init__(self)
            self.threadID = threadID
            self.name = name
            self.counter = counter
        def run(self):
            print "Starting " + self.name
            # Get lock to synchronize threads
            threadLock.acquire()
            print_time(self.name, self.counter, 3)
            # Free lock to release next thread
            threadLock.release()
    
    def print_time(threadName, delay, counter):
        while counter:
            time.sleep(delay)
            print "%s: %s" % (threadName, time.ctime(time.time()))
            counter -= 1
    
    threadLock = threading.Lock()
    threads = []
    
    # Create new threads
    thread1 = myThread(1, "Thread-1", 1)
    thread2 = myThread(2, "Thread-2", 2)
    
    # Start new Threads
    thread1.start()
    thread2.start()
    
    # Add threads to thread list
    threads.append(thread1)
    threads.append(thread2)
    
    # Wait for all threads to complete
    for t in threads:
        t.join()
    print "Exiting Main Thread"
    

利用multiprocessing多进程实现并行

  • 进程的创建
    Python 中有一套类似多线程API 的的类来进行多进程开发: multiprocessing
    这里是一个来自官方文档的例子:

    from multiprocessing import Process
    def f(name):
        print 'hello', name
    
    if __name__ == '__main__':
        p = Process(target=f, args=('bob',))
        p.start()
        p.join()
    

    类似与线程,一可以通过继承process类来实现:

    from multiprocessing import Process
    class Worker(Process):
        def run(self):
            print("in" + self.name)
    
    
    if __name__ == '__main__':
        jobs = []
        for i in range(5):
            p = Worker()
            jobs.append(p)
            p.start()
        for j in jobs:
            j.join()
    
  • 进程的通信

    • Pipe()
      pipe()函数返回一对由双向通信的管道连接的对象,这两个对象通过send, recv 方法实现 信息的传递

      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()
      
    • Quene

      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()
      
  • 进程间的同步
    Python 中多进程中也有类似线程锁的概念,使用方式几乎一样:

    from multiprocessing import Process, Lock
    def f(l, i):
        l.acquire()
        print 'hello world', i
        l.release()
    if __name__ == '__main__':
        lock = Lock()
        for num in range(10):
            Process(target=f, args=(lock, num)).start()
    
  • 进程间的共享内存
    每个进程都有独自的内存,是不能相互访问的, 也行 python官方觉得通过进程通信的方式过于麻烦,提出了共享内存的概念,以下是官方给出的例子:

    from multiprocessing import Process, Value, Array
    
    def f(n, a):
        n.value = 3.1415927
        for i in range(len(a)):
            a[i] = -a[i]
    
    if __name__ == '__main__':
        num = Value('d', 0.0)
        arr = Array('i', range(10))
    
        p = Process(target=f, args=(num, arr))
        p.start()
        p.join()
    
        print num.value
        print arr[:]
    

总结

python通过多进程实现多并行,充分利用多处理器,弥补了语言层面不支持多并行的缺点。Python, Node.js等解释型语言似乎都是通过这种方式来解决同一个时间,一个解释器只能处理一段程序的问题, 十分巧妙。

  • 5
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值