标题: python的线程处理

时间: 2013-11-06 19:05:55

正文:

python 自带的 thread 和 threading 两个线程处理模块,后者是前者的封装,一般不建议使用前者。尤其是在最新的 python 3 里,thread 已经改名 _thread 。某些情况下 thread 模块可能不存在,这时候一般使用 dummy_threading 模块来替代。

        转载请注明出处 http://blog.hickwu.com/posts/303 by Hick

一般来说,使用 threading 线程有两种方式,一种是定义线程要执行的函数,把这个函数传递进Thread对象里,让它来执行;另一种是直接从Thread继承,创建一个新的class,把线程执行的代码放到这个新的 class里。

第一种方法:

import string, threading, time

def thread_main(a):
    global count, mutex
    # 获得线程名
    threadname = threading.currentThread().getName()

    for x in xrange(0, int(a)):
        # 取得锁
        mutex.acquire()
        count = count + 1
        # 释放锁
        mutex.release()
        print threadname, x, count
        time.sleep(1)

def main(num):
    global count, mutex
    threads = []

    count = 1
    # 创建一个锁
    mutex = threading.Lock()
    # 先创建线程对象
    for x in xrange(0, num):
        threads.append(threading.Thread(target=thread_main, args=(10,)))
    # 启动所有线程
    for t in threads:
        t.start()
    # 主线程中等待所有子线程退出
    for t in threads:
        t.join()  


if __name__ == '__main__':
    num = 4
    # 创建4个线程
    main(4)

第二种方法:

import threading
import time

class Test(threading.Thread):
    def __init__(self, num):
        threading.Thread.__init__(self)
        self._run_num = num

    def run(self):
        global count, mutex
        threadname = threading.currentThread().getName()

        for x in xrange(0, int(self._run_num)):
            mutex.acquire()
            count = count + 1
            mutex.release()
            print threadname, x, count
            time.sleep(1)

if __name__ == '__main__':
    global count, mutex
    threads = []
    num = 4
    count = 1
    # 创建锁
    mutex = threading.Lock()
    # 创建线程对象
    for x in xrange(0, num):
        threads.append(Test(10))
    # 启动线程
    for t in threads:
        t.start()
    # 等待子线程结束
    for t in threads:
        t.join()  

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

Thread.getName() Thread.setName() Thread.name

  用于获取和设置线程的名称。

Thread.ident

  获取线程的识符。线程识符是一个非零整数,只有在调用了start()方法之后该属性才有效,否则它只返回None。

Thread.is_alive() Thread.isAlive()

  判断线程是否是激活的(alive)。从调用start()方法启动线程,到run()方法执行完毕或遇到未处理异常而中断 这段时间内,线程是激活的。

Thread.join([timeout])

  调用Thread.join将会使主调线程塞,直到被调用线程运行结束或超时。参数timeout是一个数值类型,表示超时时间,如果未提供该参数,那么主调线程将一直塞到被调线程结束。下面举个例子说明join()的使用:

import threading, time
def doWaiting():
    print 'start waiting:', time.strftime('%H:%M:%S')
    time.sleep(3)
    print 'stop waiting', time.strftime('%H:%M:%S')
thread1 = threading.Thread(target = doWaiting)
thread1.start()
time.sleep(1)  #确保线程thread1已经启动
print 'start join'
thread1.join()  #将一直堵塞,直到thread1运行结束。
print 'end join'

threading.RLock和threading.Lock

在threading模块中,定义两种类型的琐:threading.Lock和threading.RLock。它们之间有一点细微的区别,通过比较下面两段代码来说明:

import threading
lock = threading.Lock() #Lock对象
lock.acquire()
lock.acquire()  #产生了死琐。
lock.release()
lock.release()

import threading
rLock = threading.RLock()  #RLock对象
rLock.acquire()
rLock.acquire() #在同一线程内,程序不会堵塞。
rLock.release()
rLock.release()

这两种琐的主要区别是:RLock允许在同一线程中被多次acquire。而Lock却不允许这种情况。注意:如果使用RLock,那么acquire和release必须成对出现,即调用了n次acquire,必须调用n次的release才能真正释放所占用的琐。

threading.Condition

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

threading.Event

Event实现与Condition类似的功能,不过比Condition简单一点。它通过维护内部的标识符来实现线程间的同步问题。(threading.Event和.NET中的System.Threading.ManualResetEvent类实现同样的功能。)

threading.Timer

threading.Timer是threading.Thread的子类,可以在指定时间间隔后执行某个操作。下面是Python手册上提供的一个例子:

def hello():
    print "hello, world"
t = Timer(3, hello)
t.start() # 3秒钟之后执行hello函数。

threading.active_count() threading.activeCount()

获取当前活动的(alive)线程的个数。

threading.current_thread() threading.currentThread()

获取当前的线程对象(Thread object)。

threading.enumerate()

获取当前所有活动线程的列表。

threading.settrace(func)    设置一个跟踪函数,用于在run()执行之前被调用。

threading.setprofile(func)  

设置一个跟踪函数,用于在run()执行完毕之后调用。

python 的进程和线程

并不总是能够提高应用程序的速度,因为全局解释器锁(Global Interpreter Lock,GIL)将线程有效地限制到一个核中。如果需要使用计算机中的所有核,那么通常都需通过 fork 进程来提高速度。

特别注意,python 也是有多进程的概念: 自 2.6 版本起,Python 包括了一个名为 “多进程(multiprocessing)” 的模块来帮助处理进程。该进程模块的 API 与线程 API 的工作方式有些相似点,但是也存在一些需要特别注意的不同之处。

参考资料

查看更多文章
分享到:


分享到: