python _thread模块使用

python关于线程管理的有2个类,_thread(在2.x的版本中叫thread)和threading

# encoding: UTF-8
import thread
import time
 
# 一个用于在线程中执行的函数
def func():
    for i in range(5):
        print 'func'
        time.sleep(1)
    
    # 结束当前线程
    # 这个方法与thread.exit_thread()等价
    thread.exit() # 当func返回时,线程同样会结束
        
# 启动一个线程,线程立即开始运行
# 这个方法与thread.start_new_thread()等价
# 第一个参数是方法,第二个参数是方法的参数
thread.start_new(func, ()) # 方法没有参数时需要传入空tuple
 
# 创建一个锁(LockType,不能直接实例化)
# 这个方法与thread.allocate_lock()等价
lock = thread.allocate()
 
# 判断锁是锁定状态还是释放状态
print lock.locked()
 
# 锁通常用于控制对共享资源的访问
count = 0
 
# 获得锁,成功获得锁定后返回True
# 可选的timeout参数不填时将一直阻塞直到获得锁定
# 否则超时后将返回False
if lock.acquire():
    count += 1
    
    # 释放锁
    lock.release()
 
# thread模块提供的线程都将在主线程结束后同时结束
time.sleep(6)

输出:

Falsefunc
0
func 1
func 2
func 3
func 4

thread 模块提供的其他方法: 
thread.interrupt_main(): 在其他线程中终止主线程。 
thread.get_ident(): 获得一个代表当前线程的魔法数字,常用于从一个字典中获得线程相关的数据。这个数字本身没有任何含义,并且当线程结束后会被新线程复用。

thread还提供了一个ThreadLocal类用于管理线程相关的数据,名为 thread._local,threading中引用了这个类。

由于thread提供的线程功能不多,无法在主线程结束后继续运行,不提供条件变量等等原因,一般不使用thread模块,这里就不多介绍了。

python官网文档:

This module provides low-level primitives for working with multiple threads (also called light-weight processes or tasks) — multiple threads of control sharing their global data space. For synchronization, simple locks (also called mutexes or binary semaphores) are provided. The threading module provides an easier to use and higher-level threading API built on top of this module.

The module is optional. It is supported on Windows, Linux, SGI IRIX, Solaris 2.x, as well as on systems that have a POSIX thread (a.k.a. “pthread”) implementation. For systems lacking the _thread module, the _dummy_thread module is available. It duplicates this module’s interface and can be used as a drop-in replacement.

It defines the following constant and functions:

exception _thread.error
Raised on thread-specific errors.
_thread.LockType
This is the type of lock objects.
_thread.start_new_thread(functionargs[kwargs])
Start a new thread and return its identifier. The thread executes the function function with the argument list args (which must be a tuple). The optional kwargs argument specifies a dictionary of keyword arguments. When the function returns, the thread silently exits. When the function terminates with an unhandled exception, a stack trace is printed and then the thread exits (but other threads continue to run).
_thread.interrupt_main()
Raise a KeyboardInterrupt exception in the main thread. A subthread can use this function to interrupt the main thread.
_thread.exit()
Raise the SystemExit exception. When not caught, this will cause the thread to exit silently.
_thread.allocate_lock()
Return a new lock object. Methods of locks are described below. The lock is initially unlocked.
_thread.get_ident()
Return the ‘thread identifier’ of the current thread. This is a nonzero integer. Its value has no direct meaning; it is intended as a magic cookie to be used e.g. to index a dictionary of thread-specific data. Thread identifiers may be recycled when a thread exits and another thread is created.
_thread.stack_size([size])
Return the thread stack size used when creating new threads. The optional size argument specifies the stack size to be used for subsequently created threads, and must be 0 (use platform or configured default) or a positive integer value of at least 32,768 (32kB). If changing the thread stack size is unsupported, a ThreadError is raised. If the specified stack size is invalid, aValueError is raised and the stack size is unmodified. 32kB is currently the minimum supported stack size value to guarantee sufficient stack space for the interpreter itself. Note that some platforms may have particular restrictions on values for the stack size, such as requiring a minimum stack size > 32kB or requiring allocation in multiples of the system memory page size - platform documentation should be referred to for more information (4kB pages are common; using multiples of 4096 for the stack size is the suggested approach in the absence of more specific information). Availability: Windows, systems with POSIX threads.

Lock objects have the following methods:

lock.acquire([waitflag])
Without the optional argument, this method acquires the lock unconditionally, if necessary waiting until it is released by another thread (only one thread at a time can acquire a lock — that’s their reason for existence). If the integer waitflag argument is present, the action depends on its value: if it is zero, the lock is only acquired if it can be acquired immediately without waiting, while if it is nonzero, the lock is acquired unconditionally as before. The return value is True if the lock is acquired successfully, False if not.
lock.release()
Releases the lock. The lock must have been acquired earlier, but not necessarily by the same thread.
lock.locked()
Return the status of the lock: True if it has been acquired by some thread, False if not.

In addition to these methods, lock objects can also be used via the with statement, e.g.:

import _thread

a_lock = _thread.allocate_lock()

with a_lock:
    print("a_lock is locked while this executes")

Caveats:

  • Threads interact strangely with interrupts: the KeyboardInterrupt exception will be received by an arbitrary thread. (When thesignal module is available, interrupts always go to the main thread.)

  • Calling sys.exit() or raising the SystemExit exception is equivalent to calling _thread.exit().

  • Not all built-in functions that may block waiting for I/O allow other threads to run. (The most popular ones (time.sleep(),file.read()select.select()) work as expected.)

  • It is not possible to interrupt the acquire() method on a lock — the KeyboardInterrupt exception will happen after the lock has been acquired.

  • When the main thread exits, it is system defined whether the other threads survive. On SGI IRIX using the native thread implementation, they survive. On most other systems, they are killed without executing try ... finally clauses or executing object destructors.

  • When the main thread exits, it does not do any of its usual cleanup (except that try ... finally clauses are honored), and the standard I/O files are not flushed.

转自:http://docs.python.org/3.1/library/_thread.html

------------------------------------------------------------------------------------------------------------------------

 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()终止本线程的执行。

import _thread
import time
def threadFunction(count):
    for i in range(count):
      print('进程id为%d的打印%d'%(_thread.get_ident(),i))
      i-=1
      time.sleep(0.1)

def begin():
  ident1=_thread.start_new_thread(threadFunction,(100,))
  print('启动标识符为%d的进程'%(ident1,))
  ident2=_thread.start_new_thread(threadFunction,(100,))
  print('启动标识符为%d的进程'%(ident2,))

 
if __name__ == '__main__':
  begin()




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

class MyThread(threading.Thread):
    '''只能重写__init__ 和 run 两个方法'''
    def __init__(self,name):
        threading.Thread.__init__(self)
        self.name=name
        self.bool_stop=False
    def run(self):
        while not self.bool_stop:
            print('进程%s,于%s'%(self.name,time.asctime()))
            time.sleep(1)
    def stop(self):
        self.bool_stop = True


if __name__ == '__main__':
    th1=MyThread('one')
    th2=MyThread('two')
    th1.start()
    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操作,释放一个锁


代码如下:

import _thread,time,random
dish=0
lock = _thread.allocate_lock()
def producerFunction():
   '''如果投的筛子比0.2大,则向盘子中增加一个苹果'''
   global lock,dish
   while True:
       if(random.random() > 0.1):
         lock.acquire()
         if dish < 100:
           dish+=1
           print('生产者增加了一个苹果,现在有%d个苹果'%(dish,))
         lock.release()
         time.sleep(random.random()*3)

def consumerFunction():
  '''如果投的筛子比0.5大,则从盘子中取一个苹果'''
  global lock,dish
  while True:
    if(random.random() > 0.9):
      lock.acquire()
      if dish > 0:
        dish-=1
        print('消费者拿走一个苹果现,在有%d个苹果'%(dish,))
      lock.release()
      time.sleep(random.random()*3)

def begin():
  ident1=_thread.start_new_thread(producerFunction,())
  ident2=_thread.start_new_thread(consumerFunction,()) 
if __name__ == '__main__':
  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()
唤醒所有挂起的线程(如果存在挂起的线程)。注意:这些方法不会释放所占用的琐。

更多:

http://www.freeloong.net/20130623745.html

http://www.ibm.com/developerworks/cn/aix/library/au-threadingpython/

http://www.cnblogs.com/huxi/archive/2010/06/26/1765808.html 很好的文章

原文地址:https://www.cnblogs.com/youxin/p/3194483.html