当前位置:首页 > python > 正文内容

python多进程与多线程分析与使用(四)

xuwenyan2年前 (2021-04-10)python152

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

一、threading

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

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

#!/usr/bin/python
 # -*- coding: utf-8 -*
 __author__ = 'zni.feng'
 import  sys
 reload (sys)
 sys.setdefaultencoding('utf-8')
 
 import threading, time
 
 def test(index):
     print time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time()))
     print 'thread %s starts.' % threading.current_thread().name
     print 'the index is %d' % index
     time.sleep(3)
     print time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time()))
     print 'thread %s ends.' % threading.current_thread().name
 
 if __name__ == "__main__":
     print time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time()))
     print 'thread %s starts.' % threading.current_thread().name
     #创建线程
     my_thread = threading.Thread(target = test, args=(1,) , name= 'zni_feng_thread')
     #休眠2s
     time.sleep(2)
     #启动线程
     my_thread.start()
     #等待线程结束
     my_thread.join()
     print time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time()))
     print 'thread %s ends.' % threading.current_thread().name

输出结果为:

2021-03-12 15:06:5
thread MainThread starts.
2021-03-12 15:06:5
thread zni_feng_thread starts.
the index is 1
2021-03-12 15:06:5
thread zni_feng_thread ends.
2021-03-12 15:06:6
thread MainThread ends.
[Finished in 5.1s]

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

二、Lock

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

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

#!/usr/bin/python
 # -*- coding: utf-8 -*
 __author__ = 'zni.feng'
 import  sys
 reload (sys)
 sys.setdefaultencoding('utf-8')
 import threading
 
 class Account:
     def __init__(self):
         self.balance = 0
 
     def add(self):
         for i in range(0,100000):
             self.balance += 1
 
     def delete(self):
         for i in range(0,100000):
             self.balance -=1 
 
 if __name__ == "__main__":
     account  = Account()
     #创建线程
     thread_add = threading.Thread(target=account.add, name= 'Add')
     thread_delete = threading.Thread(target=account.delete, name= 'Delete')
 
     #启动线程
     thread_add.start()
     thread_delete.start()
 
     #等待线程结束
     thread_add.join()
     thread_delete.join()
 
     print 'The final balance is: ' + str(account.balance)

运行结果为:

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

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

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

 #!/usr/bin/python
 # -*- coding: utf-8 -*
 __author__ = 'zni.feng'
 import  sys
 reload (sys)
 sys.setdefaultencoding('utf-8')
 import threading
 
 class Account:
     def __init__(self):
         self.balance = 0
 
     def add(self, lock):
         #获得锁
         lock.acquire()
         for i in range(0,100000):
             self.balance += 1
         #释放锁
         lock.release()
 
     def delete(self, lock):
         #获得锁
         lock.acquire()
         for i in range(0,100000):
             self.balance -=1
         #释放锁
         lock.release()
 
 if __name__ == "__main__":
     account  = Account()
     lock = threading.Lock()
     #创建线程
     thread_add = threading.Thread(target=account.add, args=(lock, ), name= 'Add')
     thread_delete = threading.Thread(target=account.delete, args=(lock, ), name= 'Delete')
 
     #启动线程
     thread_add.start()
     thread_delete.start()
 
     #等待线程结束
     thread_add.join()
     thread_delete.join()
 
     print 'The final balance is: ' + str(account.balance)

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

The final balance is: 0
[Finished in 0.1s]


    文章作者:xuwenyan
    版权声明:本文为本站原创文章,转载请注明出处,非常感谢,如版权漏申明或您觉得任何有异议的地方欢迎与本站取得联系。

    扫描二维码推送至手机访问。

    版权声明:本文由艺文笔记发布,如需转载请注明出处。

    本文链接:https://www.xuwenyan.com/archives/1662

    分享给朋友:

    “python多进程与多线程分析与使用(四)” 的相关文章

    python3使用requests通过get和post获取url网页内容

    python3使用requests通过get和post获取url网页内容

    python3如何通过get或post的方式获取url内容?如网页内容。下面使用的是python3.7版本。 我们需要用到的一个库是requests,这个库是python自带的,不需要安装,使用非常方便。 这里随便提一下,如果不知道如何安装python三方模块请参阅:https://w...

    python多进程与多线程分析与使用(一)

    python多进程与多线程分析与使用(一)

      进程是一个执行中的程序,每个进程有自己的地址空间、内存、数据栈以及其他用于跟踪执行的辅助数据。操作系统管理其上所有进程,并合理分配时间。进程也可以通过fork或spawn派生新的进程,每个新进程有自己的内存数据栈,所以只能采用进程间通信(IPC)的方式共享信息。  多线程模块:...

    Python如何打包成可执行程序exe直接运行?

    Python如何打包成可执行程序exe直接运行?

    Python如何打包成可执行程序exe直接运行? 安装pyinstaller 首先安装pyinstaller,使用安装命令:pip3 install pyinstaller,如下图所示。 Pyinstaller打包exe 1:直接打开cmd到脚本目录下,执行命令:p...

    python获取命令参数报错index out of range

    python获取命令参数报错index out of range

    python获取命令行参数的方法import sys sys.argv[index] // index is 0 1 2....报错index out of range大多数解决方案都是说你没有传递足够的参数,这是原因之一,但是...

    Python常用方法整理(路径、文件、编码格式等)

    Python常用方法整理(路径、文件、编码格式等)

    获得工作路径import os work_path = os.getcwd()设置工作路径import os os.chdir('d:\\test')获取脚本所在路径import os current_path =&n...