4.python学习笔记:python多线程下的threading模块

python多线程下的threading模块


threading模块

在python编程中对于线程的处理有两个模块:thread和threading,在上一个章节中我们介绍了thread的用法,它是一种较为底层的基本接口,在threading中对于线程的处理是基于类和对象的较高层面接口。其实本质上threading模块在内部使用thread模块来实现代表线程的对象以及常用的同步化工具。

对于上一章的示例我们采用threading再次进行封装:

#!/usr/bin/env python

#-*-coding:utf-8-*-

import threading

class My_thread(threading.Thread):

    def __init__(self, my_id, count, mutex):
        self.my_id = my_id
        self.count = count
        self.mutex = mutex
        threading.Thread.__init__(self)

    def run(self):
        for i in range(self.count):
            with self.mutex:
                print ('[%s] => %s' % (self.my_id, i))

stdout_mutex = threading.Lock()
threads = []

if __name__ == '__main__':
    #start and append threads
    for i in range(10):
        thread = My_thread(i, 5, stdout_mutex)
        thread.start()
        threads.append(thread)


    #wait for thread ending...
    for thread in threads:
        thread.join()

    print ('Main thread exiting...')

这里我们使用join来接收线程结束时返回的状态,好让主线程在其他线程都结束后再退出程序。
当我们创建一个My_thread类对象并且调用其start方法时,run方法将会在新的线程中在Thread类框架中得以执行。

这个脚本中还使用了threading.Lock()进行了操作的同步化。

之前我们可能到线程中的打印操作需要用锁进行同步,因为stdout这种文件描述符资源也是各个线程之间共享的,由此可以看出线程需要通过他们对于任何可能在同一进程中的共享项目进行同步化,这些对象包括:

1.内存中的可变对象
2.全局作用域中的名称
3.模块中的内容

例如我们对一个整数进行自增1运算,派生出100个线程,每个线程对该值的自增运行2次。代码示例如下:

#!/usr/bin/env python

#-*-coding:utf-8-*-

import threading
import time

count = 0

def adder(add_lock):
    global count
    with add_lock:
        count = count + 1
    time.sleep(0.25)
    with add_lock:
        count = count + 1

add_lock = threading.Lock()

if __name__ == '__main__':
    threads = []
    for i in range(100):
        thread = threading.Thread(target=adder, args=(add_lock,))
        thread.start()
        threads.append(thread)

    for thread in threads:
        thread.join()

    print(count)

threading的更多接口

*以下转载伯乐在线内容

threading.Thread

Thread 是threading模块中最重要的类之一,可以使用它来创建线程。有两种方式来创建线程:一种是通过继承Thread类,重写它的run方法;另一种是创建一个threading.Thread对象,在它的初始化函数(init)中将可调用对象作为参数传入。下面分别举例说明。先来看看通过继承threading.Thread类来创建线程的例子:

#coding=gbk
import threading, time, random
count = 0
class Counter(threading.Thread):
    def __init__(self, lock, threadName):
        '''@summary: 初始化对象。

        @param lock: 琐对象。
        @param threadName: 线程名称。
        '''
        super(Counter, self).__init__(name = threadName)  #注意:一定要显式的调用父类的初始
化函数。
        self.lock = lock

    def run(self):
        '''@summary: 重写父类run方法,在线程启动后执行该方法内的代码。
        '''
        global count
        self.lock.acquire()
        for i in xrange(10000):
            count = count + 1
        self.lock.release()
lock = threading.Lock()
for i in range(5):
    Counter(lock, "thread-" + str(i)).start()
time.sleep(2)   #确保线程都执行完毕
print count

在代码中,我们创建了一个Counter类,它继承了threading.Thread。初始化函数接收两个参数,一个是琐对象,另一个是线程的名称。在Counter中,重写了从父类继承的run方法,run方法将一个全局变量逐一的增加10000。在接下来的代码中,创建了五个Counter对象,分别调用其start方法。最后打印结果。这里要说明一下run方法 和start方法: 它们都是从Thread继承而来的,run()方法将在线程开启后执行,可以把相关的逻辑写到run方法中(通常把run方法称为活动[Activity]。);start()方法用于启动线程。

再看看另外一种创建线程的方法:

import threading, time, random
count = 0
lock = threading.Lock()
def doAdd():
    '''@summary: 将全局变量count 逐一的增加10000。
    '''
    global count, lock
    lock.acquire()
    for i in xrange(10000):
        count = count + 1
    lock.release()
for i in range(5):
    threading.Thread(target = doAdd, args = (), name = 'thread-' + str(i)).start()
time.sleep(2)   #确保线程都执行完毕
print count

在这段代码中,我们定义了方法doAdd,它将全局变量count 逐一的增加10000。然后创建了5个Thread对象,把函数对象doAdd 作为参数传给它的初始化函数,再调用Thread对象的start方法,线程启动后将执行doAdd函数。这里有必要介绍一下threading.Thread类的初始化函数原型:

def init(self, group=None, target=None, name=None, args=(), kwargs={})
  参数group是预留的,用于将来扩展;
  参数target是一个可调用对象(也称为活动[activity]),在线程启动后执行;
  参数name是线程的名字。默认值为“Thread-N“,N是一个数字。
  参数args和kwargs分别表示调用target时的参数列表和关键字参数。


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的用法。


threading.RLock和threading.Lock

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


threading模块中还有一些常用的方法没有介绍:
threading.active_count()
threading.activeCount()

获取当前活动的(alive)线程的个数。
threading.current_thread()
threading.currentThread()

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

获取当前所有活动线程的列表。
threading.settrace(func)

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

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


关于python上threading模块的使用可以查看python手册进行更加细致的学习:
https://docs.python.org/2/library/threading.html#module-threading

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值