zoukankan      html  css  js  c++  java
  • Python中的多进程与多线程(二)

      在上一章中,学习了Python多进程编程的一些基本方法:使用跨平台多进程模块multiprocessing提供的Process、Pool、Queue、Lock、Pipe等类,实现子进程创建、进程池(批量创建子进程并管理子进程数量上限)以及进程间通信。这一章学习下Python下的多线程编程方法。

    一、threading

    线程是操作系统执行任务的最小单元。Python标准库中提供了threading模块,对多线程编程提供了很便捷的支持。

    下面是使用threading实现多线程的代码:

     1 #!/usr/bin/python
     2 # -*- coding: utf-8 -*
     3 __author__ = 'zni.feng'
     4 import  sys
     5 reload (sys)
     6 sys.setdefaultencoding('utf-8')
     7 
     8 import threading, time
     9 
    10 def test(index):
    11     print time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time()))
    12     print 'thread %s starts.' % threading.current_thread().name
    13     print 'the index is %d' % index
    14     time.sleep(3)
    15     print time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time()))
    16     print 'thread %s ends.' % threading.current_thread().name
    17 
    18 if __name__ == "__main__":
    19     print time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time()))
    20     print 'thread %s starts.' % threading.current_thread().name
    21     #创建线程
    22     my_thread = threading.Thread(target = test, args=(1,) , name= 'zni_feng_thread')
    23     #等待2s
    24     time.sleep(2)
    25     #启动线程
    26     my_thread.start()
    27     #等待线程结束
    28     my_thread.join()
    29     print time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time()))
    30     print 'thread %s ends.' % threading.current_thread().name

    输出结果为:

    2017-01-12 22:06:32
    thread MainThread starts.
    2017-01-12 22:06:34
    thread zni_feng_thread starts.
    the index is 1
    2017-01-12 22:06:37
    thread zni_feng_thread ends.
    2017-01-12 22:06:37
    thread MainThread ends.
    [Finished in 5.1s]

     其中,threading模块的current_thread()函数会返回当前线程的实例。

    二、Lock

    多进程与多线程的最大不同在于,多进程中,同一个变量,各自有一份拷贝存在于每个进程中,互不影响。而多线程中,所有变量都由所有线程共享,所以,任何一个共享变量都可以被任何一个线程修改。因此线程之间共享数据最大的危险在于多个线程同时改变一个变量。为了解决这个问题,我们可以借助于threading模块的Lock类给共享变量加锁。

    先看看使用多线程写同一个共享变量,不加锁的例子:

     1 #!/usr/bin/python
     2 # -*- coding: utf-8 -*
     3 __author__ = 'zni.feng'
     4 import  sys
     5 reload (sys)
     6 sys.setdefaultencoding('utf-8')
     7 import threading
     8 
     9 class Account:
    10     def __init__(self):
    11         self.balance = 0
    12 
    13     def add(self):
    14         for i in range(0,100000):
    15             self.balance += 1
    16 
    17     def delete(self):
    18         for i in range(0,100000):
    19             self.balance -=1 
    20 
    21 if __name__ == "__main__":
    22     account  = Account()
    23     #创建线程
    24     thread_add = threading.Thread(target=account.add, name= 'Add')
    25     thread_delete = threading.Thread(target=account.delete, name= 'Delete')
    26 
    27     #启动线程
    28     thread_add.start()
    29     thread_delete.start()
    30     
    31     #等待线程结束
    32     thread_add.join()
    33     thread_delete.join()
    34 
    35     print 'The final balance is: ' + str(account.balance)

    运行结果为:

    The final balance is: -51713
    [Finished in 0.1s]

    可以发现,每次运行,它的最终结果都会不同,而且都不是0。就是因为不同线程在同时修改同一个变量时,发生了冲突,某些中间变量没有按顺序被使用导致。

    现在我们使用Lock对程序进行加锁:

     1 #!/usr/bin/python
     2 # -*- coding: utf-8 -*
     3 __author__ = 'zni.feng'
     4 import  sys
     5 reload (sys)
     6 sys.setdefaultencoding('utf-8')
     7 import threading
     8 
     9 class Account:
    10     def __init__(self):
    11         self.balance = 0
    12 
    13     def add(self, lock):
    14         #获得锁
    15         lock.acquire()
    16         for i in range(0,100000):
    17             self.balance += 1
    18         #释放锁
    19         lock.release()
    20 
    21     def delete(self, lock):
    22         #获得锁
    23         lock.acquire()
    24         for i in range(0,100000):
    25             self.balance -=1 
    26         #释放锁
    27         lock.release()
    28 
    29 
    30 if __name__ == "__main__":
    31     account  = Account()
    32     lock = threading.Lock()
    33     #创建线程
    34     thread_add = threading.Thread(target=account.add, args=(lock, ), name= 'Add')
    35     thread_delete = threading.Thread(target=account.delete, args=(lock, ), name= 'Delete')
    36 
    37     #启动线程
    38     thread_add.start()
    39     thread_delete.start()
    40     
    41     #等待线程结束
    42     thread_add.join()
    43     thread_delete.join()
    44 
    45     print 'The final balance is: ' + str(account.balance)

    可以发现,无论如何执行多少次,balance结果都为0。如果将每次balance计算的结果都打印出来,还会发现,当一个线程开始执行时,另一个线程一定会等到前一个线程执行完(准确地说是lock.release()执行完)后才开始执行。

    The final balance is: 0
    [Finished in 0.1s]
  • 相关阅读:
    Linux内核分析— —操作系统是如何工作的(20135213林涵锦)
    【BARTS计划】【Share_Week1】社交产品思考
    【BARTS计划】【Tips_Week1】20190331更新
    【BARTS计划】【Review_Week1】Google Docs 成为青少年们喜爱的聊天 app
    【学习博客】Python学习初体验
    《构建之法》读书笔记5
    《构建之法》8&16
    《构建之法》读书笔记4
    《构建之法》读书笔记3
    《构建之法》读书笔记2
  • 原文地址:https://www.cnblogs.com/znicy/p/6279930.html
Copyright © 2011-2022 走看看