欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2024-01-25 20:36:22
...

多线程与多进程

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