Python基础教程之多线程与多进程

Posted ProChick

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python基础教程之多线程与多进程相关的知识,希望对你有一定的参考价值。

多线程与多进程

1.有关多线程

线程是CPU进行资源分配和调度的基本单位,共享进程的内存,一个进程必须至少有一个线程

  • 基本代码示例

    import threading
    import time
    
    def test1():
        print('唱歌')
    def test2():
        print('跳舞')
        
    task1 = threading.Thread(target = test1)
    task2 = threading.Thread(target = test2)
    
    task1.start()
    task2.start()
    
  • 线程共享代码示例

    • 正常情况下

      import threading,time
      
      ticket = 10
      
      def sale():
          global ticket
          while True:
              if ticket > 0:
                  # time.sleep(0.2)
                  ticket -= 1
                  print('{0}卖了1张票,还剩下{1}张票'.format(threading.current_thread().name, 
                                                   ticket))
              else:
                  print('票卖完了')
                  break
      
      task1 = threading.Thread(target=sale, name='窗口1')
      task2 = threading.Thread(target=sale, name='窗口2')
      
      task1.start()
      task2.start()
      
      窗口1卖了1张票,还剩下9张票
      窗口1卖了1张票,还剩下8张票
      窗口1卖了1张票,还剩下7张票
      窗口1卖了1张票,还剩下6张票
      窗口1卖了1张票,还剩下5张票
      窗口1卖了1张票,还剩下4张票
      窗口1卖了1张票,还剩下3张票
      窗口1卖了1张票,还剩下2张票
      窗口1卖了1张票,还剩下1张票
      窗口1卖了1张票,还剩下0张票
      票卖完了
      票卖完了
      
    • 当上面的代码有time延时则会出现以下问题

      窗口1卖了1张票,还剩下9张票
      窗口2卖了1张票,还剩下8张票
      窗口1卖了1张票,还剩下7张票
      窗口2卖了1张票,还剩下6张票
      窗口1卖了1张票,还剩下5张票
      窗口2卖了1张票,还剩下4张票
      窗口1卖了1张票,还剩下3张票
      窗口2卖了1张票,还剩下2张票
      窗口1卖了1张票,还剩下1张票
      窗口2卖了1张票,还剩下0张票
      票卖完了
      窗口1卖了1张票,还剩下-1张票
      票卖完了
      
  • 利用线程锁来解决上面出现的问题

    import threading,time
    
    ticket = 10
    lock = threading.Lock()
    
    def sale():
        global ticket
        global lock
        
        while True:
            # 上锁
            lock.acquire()
            
            if ticket > 0:
                time.sleep(0.2)
                ticket -= 1
                print('{0}卖了1张票,还剩下{1}张票'.format(threading.current_thread().name, 
                                                 ticket))
            else:
                print('票卖完了')
                break
                
            # 解锁
            lock.release()
    
    task1 = threading.Thread(target=sale, name='窗口1')
    task2 = threading.Thread(target=sale, name='窗口2')
    
    task1.start()
    task2.start()
    
    窗口1卖了1张票,还剩下9张票
    窗口2卖了1张票,还剩下8张票
    窗口1卖了1张票,还剩下7张票
    窗口2卖了1张票,还剩下6张票
    窗口1卖了1张票,还剩下5张票
    窗口2卖了1张票,还剩下4张票
    窗口1卖了1张票,还剩下3张票
    窗口2卖了1张票,还剩下2张票
    窗口1卖了1张票,还剩下1张票
    窗口2卖了1张票,还剩下0张票
    票卖完了
    票卖完了
    
  • 线程之间通信的代码示例

    import threading,time,queue
    
    def produce():
        for i in range(1,11):
            time.sleep(1)
            print('生产出{}号产品'.format(i))
            q.put('p' + str(i))
            
    def consume():
        while True:
            time.sleep(0.5)
            print('消耗掉产品' + q.get())
    
    q = queue.Queue()
    
    task1 = threading.Thread(target=produce, name='生产者')
    task2 = threading.Thread(target=consume, name='消费者')
    
    task1.start()
    task2.start()
    

2.有关多进程

进程是系统进行资源分配和调度的基本单位,拥有独立的内存单元,一个程序必须至少有一个进程

  • 基本代码示例

    利用进程执行任务

    import multiprocessing as mp
    import time, os
    
    def test1(n):
        for i in range(n):
        	time.sleep(1)
            print('唱歌,进程ID:{}'.format(os.getpid()))
        
    def test2(n):
        for i in range(n):
        	time.sleep(1)
       		print('跳舞,进程ID:{}'.format(os.getpid()))
        
    if __name__ == __main__
        p1 = mp.Process(target = test1, args = (10,))
        p2 = mp.Process(target = test2, args = (20,))
    
        p1.start()
        p2.start()
    
  • 进程之间不共享的代码示例

    进程间默认是不能共享数据的

    import multiprocessing as mp
    import os
    
    n = 0
    
    def test1():
        global n
        n += 1
        print('n={},进程ID:{}'.format(n, os.getpid()))
        
    def test2():
        global n
        n += 1
        print('n={},进程ID:{}'.format(n, os.getpid()))
        
    if __name__ == __main__
        p1 = mp.Process(target = test1)
        p2 = mp.Process(target = test2)
    
        p1.start() # n=1
        p2.start() # n=1
    
  • 进程之间实现共享的代码示例

    Manager对象提供了不同进程间共享数据的方式

    from multiprocessing import Process, Manager
    
    def test(list):
        list.reverse()
        
    if __name__ == __main__
    	manager = Manager()
        list = manager.list(range(5))
        
        p = mp.Process(target = test, args=(list,))
        p.start()
        p.join()
        
        print(list) # [4,3,2,1,0]
    
  • 进程之间通信的代码示例

    利用Queue队列实现进程间共享数据通信

    import multiprocessing as mp
    import os
    import time
    
    def produce(q):
        for i in range(1,11):
            time.sleep(1)
            print('生产出{}号产品,pid={}'.format(i, os.getpid()))
            q.put('p' + str(i))
            
    def consume(q):
        while True:
            time.sleep(0.5)
            print('消耗掉{}号产品,pid={}'.format(q.get(), os.getpid()))
    
    if __name__ == '__main__'
        q = mp.Queue()
    
        task1 = mp.Process(target = produce, args = (q,))
        task1 = mp.Process(target = consume, args = (q,))
    
        task1.start()
        task2.start()
    
  • 进程之间进行远程通信的代码示例

    利用Listener和Client对象实现进程间远程通信

    # 服务器端
    from multiprocessing.connection import Listener
    
    listener = Listener(('127.0.0.1',8080), authkey='123')
    conn = listener.accept()
    print('连接来自:',listener.last_accepted)
    conn.send([1,2,3])
    conn.send_bytes('hello')
    
    conn.close()
    listener.close()
    
    # 客户端
    from multiprocessing.connection import Client
    
    conn = Client(('127.0.0.1',8080), authkey='123')
    print(conn.recv())          # [1,2,3]
    print(conn.recv_bytes())    # hello
    
    conn.close()
    
  • 进程池的使用代码示例

    from multiprocessing import Pool
    import os, time, random
    
    def work(msg):
        start = time.time()
        print('执行{},进程号为{}'.format(msg,os.getpid())
       	time.sleep(random.random()*2)
        end = time.time()
        print('{}执行完毕,耗时{}'.format(msg,start-end))
              
    po = Pool(3)
    for i in range(0,10):
        po.apply_async(work,(i,))
              
    po.close()
    po.join()
    

以上是关于Python基础教程之多线程与多进程的主要内容,如果未能解决你的问题,请参考以下文章

python-学习-python并发编程之多进程与多线程

编程思想之多线程与多进程——Java中的多线程

网络编程之多线程——多线程与多进程的区别

多进程(mutiprocessing)与多线程(Threading)之多线程

[转帖]编程思想之多线程与多进程——以操作系统的角度述说线程与进程

编程思想之多线程与多进程系列