Python多线程和Python的锁

Python多线程 
Python中实现多线程有两种方式,一种基于_thread模块(在Python2.x版本中为thread模块,没有下划线)的start_new_thread()函数,另一种基于threading模块的Thread类。 
其实Python的多线程编程不能真正利用多核的CPU,但是用开源模块使你的计算压力分布到多核CPU上.........

一.使用start_new_thread()实现线程,是比较底层的实现方式,所有线程共享他们global数据,为了达到同步,模块也提供了简单的锁机制

_thread.start_new_thread(function, args[, kwargs])
启动一个新的进程,并返回其标识符. 线程执行的函数需要的参数由args(必须为一个元组)提供,亦可通过可选参数kwargs提供关键字参数组  成的字典。当函数返回时,启动的线程也   停止退出。如果函数中存在未处理异常,会打印堆栈跟踪后线程停止退出(其他线程继续执行)。

其中线程标识符是一个非0整数,并没有直接意思,可以当作从一个线程组成的特殊字典中索引本线程的一个key,也可用_thread.get_ident()得到,在线程退出后,标识符会被系统回收。在线程执行过程中可以调用_thread.exit()终止本线程的执行。

Java代码  

  1. import _thread
  2. import time
  3. def threadFunction(count):
  4. for i in range(count):
  5. print(‘进程id为%d的打印%d‘%(_thread.get_ident(),i))
  6. i-=1
  7. time.sleep(0.1)
  8. def begin():
  9. ident1=_thread.start_new_thread(threadFunction,(100,))
  10. print(‘启动标识符为%d的进程‘%(ident1,))
  11. ident2=_thread.start_new_thread(threadFunction,(100,))
  12. print(‘启动标识符为%d的进程‘%(ident2,))
  13. if __name__ == ‘__main__‘:
  14. begin()

二.使用Thread类来实现多线程,这种方式是对_thread模块(如果没有_thread,则为dummy_threading)的高级封装,在这种方式下我们需创建新类继承threading.Thread,和java一样重写threading.Thread的run方法即可.启动线程用线程的start方法,它会调用我们重写的run方法.

Java代码  

  1. class MyThread(threading.Thread):
  2. ‘‘‘只能重写__init__ 和 run 两个方法‘‘‘
  3. def __init__(self,name):
  4. threading.Thread.__init__(self)
  5. self.name=name
  6. self.bool_stop=False
  7. def run(self):
  8. while not self.bool_stop:
  9. print(‘进程%s,于%s‘%(self.name,time.asctime()))
  10. time.sleep(1)
  11. def stop(self):
  12. self.bool_stop = True
  13. if __name__ == ‘__main__‘:
  14. th1=MyThread(‘one‘)
  15. th2=MyThread(‘two‘)
  16. th1.start()
  17. th2.start()

Thread类还定义了以下常用方法与属性:

Thread.getName() \Thread.setName()
老方式用于获取和设置线程的名称,官方建议用Thread.name替代
Thread.ident
获取线程的标识符。只有在调用start()方法执行后才有效,否则返回None。
Thread.is_alive()
判断线程是否是激活的。
Thread.join([timeout])
调用Thread.join将会使主调线程堵塞,直到被调用线程运行结束或超时。参数timeout是一个数值类型,表示超时时间,如果未提供该参数,那么主调线程将一直堵塞到被调线程结束。

Python中的锁

先用_thread模块的Lock锁来实现生产者消费者问题,Lock对象是Python提供的低级线程控制工具,使用起来非常简单,只需下面3条语句即可:

_thread.allocate_lock()返回一个新Lock对象,即为一个新锁
lock.acquire() 相当于P操作,得到一个锁,
lock.release()相当于V操作,释放一个锁

代码如下:

Java代码  

  1. import _thread,time,random
  2. dish=0
  3. lock = _thread.allocate_lock()
  4. def producerFunction():
  5. ‘‘‘如果投的筛子比0.2大,则向盘子中增加一个苹果‘‘‘
  6. global lock,dish
  7. while True:
  8. if(random.random() > 0.1):
  9. lock.acquire()
  10. if dish < 100:
  11. dish+=1
  12. print(‘生产者增加了一个苹果,现在有%d个苹果‘%(dish,))
  13. lock.release()
  14. time.sleep(random.random()*3)
  15. def consumerFunction():
  16. ‘‘‘如果投的筛子比0.5大,则从盘子中取一个苹果‘‘‘
  17. global lock,dish
  18. while True:
  19. if(random.random() > 0.9):
  20. lock.acquire()
  21. if dish > 0:
  22. dish-=1
  23. print(‘消费者拿走一个苹果现,在有%d个苹果‘%(dish,))
  24. lock.release()
  25. time.sleep(random.random()*3)
  26. def begin():
  27. ident1=_thread.start_new_thread(producerFunction,())
  28. ident2=_thread.start_new_thread(consumerFunction,())
  29. if __name__ == ‘__main__‘:
  30. begin()

另一个较高级的锁为RLock锁,RLock对象内部维护着一个Lock对象,它是一种可重入的对象。对于Lock对象而言,如果一个线程连续两次进行acquire操作,那么由于第一次acquire之后没有release,第二次acquire将挂起线程。这会导致Lock对象永远不会release,使得线程死锁。RLock对象允许一个线程多次对其进行acquire操作,因为在其内部通过一个counter变量维护着线程acquire的次数。而且每一次的acquire操作必须有一个release操作与之对应,在所有的release操作完成之后,别的线程才能申请该RLock对象。

threading模块对Lock也提供和封装,提供了更高级的同步方式(可以理解为更高级的锁),包括threading.Event和threading.Condition,其中threading.Event为提供了简单的同步方式:一个进程标记event,其他进程等待,只需下面的几个方法即可:

Event.wait([timeout])
堵塞线程,直到Event对象内部标识位被设为True或超时(如果提供了参数timeout)。
Event.set()
将标识号设为Ture
Event.clear()
设为标识符False

threading.Condition 可以把Condiftion理解为一把高级的琐,它提供了比Lock, RLock更高级的功能,允许我们能够控制复杂的线程同步问题。threadiong.Condition在内部维护一个琐对象(默认是RLock),可以在创建Condigtion对象的时候把琐对象作为参数传入。Condition也提供了acquire, release方法,其含义与琐的acquire, release方法一致,其实它只是简单的调用内部琐对象的对应的方法而已。Condition还提供了如下方法(特别要注意:这些方法只有在占用琐(acquire)之后才能调用,否则将会报RuntimeError异常。):

Condition.wait([timeout]):    
wait方法释放内部所占用的琐,同时线程被挂起,直至接收到通知被唤醒或超时(如果提供了timeout参数的话)。当线程被唤醒并重新占有琐的时候,程序才会继续执行下去。
Condition.notify():  
唤醒一个挂起的线程(如果存在挂起的线程)。注意:notify()方法不会释放所占用的琐。
Condition.notify_all()
唤醒所有挂起的线程(如果存在挂起的线程)。注意:这些方法不会释放所占用的琐。
时间: 2024-07-28 18:07:03

Python多线程和Python的锁的相关文章

Python多线程(threading)学习总结

注:此文除了例子和使用心得是自己写的,很多都是Python核心编程中的原文.原文文风应该能看出来,就不每个地方单独表明出处了. 线程(有时被称为轻量级进程)跟进程有些相似,不同的是,所有的线程运行在同一个进程中,共享相同的运行环境.它们可以想像成是在主进程或"主线程"中并行运行的"迷你进程". 线程有开始,顺序执行和结束三部分.它有一个自己的指令指针,记录自己运行到什么地方.线程的运行可能被抢占(中断),或暂时的被挂起(也叫睡眠),让其它的线程运行,这叫做让步.一个

python多线程同步实例分析

进程之间通信与线程同步是一个历久弥新的话题,对编程稍有了解应该都知道,但是细说又说不清.一方面除了工作中可能用的比较少,另一方面就是这些概念牵涉到的东西比较多,而且相对较深.网络编程,服务端编程,并发应用等都会涉及到.其开发和调试过程都不直观.由于同步通信机制的原理都是想通的,本文希通过望借助python实例来将抽象概念具体化. 阅读之前可以参考之前的一篇文章:python多线程与多进程及其区别,了解一下线程和进程的创建. python多线程同步 python中提供两个标准库thread和thr

python多线程的几种方法

python多线程编程 Python多线程编程中常用方法: 1.join()方法:如果一个线程或者在函数执行的过程中调用另一个线程,并且希望待其完成操作后才能执行,那么在调用线程的时就可以使用被调线程的join方法join([timeout]) timeout:可选参数,线程运行的最长时间 2.isAlive()方法:查看线程是否还在运行 3.getName()方法:获得线程名 4.setDaemon()方法:主线程退出时,需要子线程随主线程退出,则设置子线程的setDaemon() Pytho

Python多线程锁

[Python之旅]第六篇(四):Python多线程锁 python lock 多线程 多线程使用方法 多线程锁 摘要:   在多线程程序执行过程中,为什么需要给一些线程加锁以及如何加锁,下面就来说一说. 1.给线程加锁的原因     我们知道,不同进程之间的内存空间数据是不能够共享的,试想一下,如果可以随意共享,谈何安全?但是一个进程中的多个线程是可以共享这个进程的内存空间中的数据的,比如多个线程可以同时调用某一... 在多线程程序执行过程中,为什么需要给一些线程加锁以及如何加锁,下面就来说一

【Python之旅】第六篇(四):Python多线程锁

    在多线程程序执行过程中,为什么需要给一些线程加锁以及如何加锁,下面就来说一说. 1.给线程加锁的原因 我们知道,不同进程之间的内存空间数据是不能够共享的,试想一下,如果可以随意共享,谈何安全?但是一个进程中的多个线程是可以共享这个进程的内存空间中的数据的,比如多个线程可以同时调用某一内存空间中的某些数据(只是调用,没有做修改). 试想一下,在某一进程中,内存空间中存有一个变量对象的值为num=8,假如某一时刻有多个线程需要同时使用这个对象,出于这些线程要实现不同功能的需要,线程A需要将n

[ Python - 11 ] 多线程及GIL全局锁

1. GIL是什么? 首先需要明确的一点是GIL并不是python的特性, 它是在实现python解析器(Cpython)时所引入的一个概念. 而Cpython是大部分环境下默认的python执行环境,要明确一点:GIL并不是python的特性,python完全可以不依赖于GIL. 2. 为什么会有GIL? 为了更有效的利用多核处理器的性能,就出现了多线程的编程方式,而随之带来的就是线程间数据的一致性和状态同步的完整性 (例如:线程2需要线程1执行完成的结果,然而线程2又比线程1代码量少,线程2

python 并发编程 多线程 GIL全局解释器锁基本概念

首先需要明确的一点是GIL并不是Python的特性,它是在实现Python解析器(CPython)时所引入的一个概念. 就好比C++是一套语言(语法)标准,但是可以用不同的编译器来编译成可执行代码. >有名的编译器例如GCC,INTEL C++,Visual C++等.Python也一样,同样一段代码可以通过CPython,PyPy,Psyco等不同的Python执行环境来执行. 像其中的JPython就没有GIL.然而因为CPython是大部分环境下默认的Python执行环境.所以在很多人的概

python多线程、多进程以及GIL

多线程 使用threading模块创建线程 传入一个函数 这种方式是最基本的,即调用threading中的Thread类的构造函数,然后指定参数target=func,再使用返回的Thread的实例调用start()方法,即开始运行该线程,该线程将执行函数func,当然,如果func需要参数,可以在Thread的构造函数中传入参数args=(-).示例代码如下 import threading #用于线程执行的函数 def counter(n): cnt = 0; for i in xrange

python多线程学习记录

1.多线程的创建 import threading t = t.theading.Thread(target, args--) t.SetDeamon(True)//设置为守护进程 t.start(),启动线程 t.join(),阻塞当前线程,即使得在当前线程结束时,不会退出.会等到子线程结束之后才退出. 如果不加join语句,主线程不会等到子线程结束才结束,但却不会立即杀死该线程. 但是如果添加了SetDaemon(True),如果不加join,则会在主线程结束后马上杀死子线程. 如果join