`
这些年
  • 浏览: 397828 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

多线程(转)

 
阅读更多

设置线程名称

 

Thread.currentThread().setName("hello");
System.out.println(Thread.currentThread().getName());

 

 

1:原理

python对于多线程的实现,主要依靠模块threading和thread。其中threading是一个高层模块,对较为底层的thread进行了一些必要的封装。

 下面来看看threading模块中的几个方法吧。

    threading.active_count()  返回当前处于alive状态的Thread对象的个数。

    threading.current_thread() 返回当前Thread对象。

    threading.enumerate() 返回当前处于alive状态的Thread对象的集合。

 

Thread 对象

这是python多线程机制的核心类。每个线程都是Thread对象。

下面对其方法作一下介绍。

class threading.Thread(group=None, target=None, name=None, args=(), kwargs={})

在使用该构造函数时,参数的设置必须显式地进行。

group 默认为None,预留的扩展参数以应对ThreadGroup类的实现。

target 一个被run()方法调用的可运行的对象,方法也是对象哦。默认为None,也就是run不做任何操作。

name 线程名称。默认情况下,会被构造函数创建一个"Thread-N"的名称,N

是一个小的数字。

args 是target指向的运行对象的参数元组。默认是()。

kwargs 是target指向的运行对象的字典参数。默认为{},其功能与args是一致的。

如果子类想继承Thread类,必须首先执行Thread.__init__()方法。

start()

激活线程。它做的事情其实就是调用该线程对象的run()方法。

run()

运行线程。如果采用继承的方式来创建多线程,必须重写此方法。

join(timeout=None)

等待直到该线程终结。该方法会使得调用该线程的调用者处于等待状态,直到该线程运行完。

如果timeout参数被设置,则表示在timeout秒内,如果该线程依然未终结,则调用者也会执行下面的逻辑。这个时候,可以使用is_alive()方法来判断该线程是否执行完毕。

name

线程名,在多线程中,该属性的值并不唯一。

ident

用来标识一个线程。在该线程start之前,该属性的值为None,线程开始之后会被赋值,即使在线程结束之后,该值依然有效。

is_alive()

判断线程是否alive。alive状态是指线程start()执行之后而run()方法未执行完之前的状态。daemon

布尔值。True表示为守护线程。该线程的设置必须在start()之前。初始值从你线程继承而来,主线程为非daemon线程。

 

对于共享数据的同步问题,我们选两个比较常用的方法来解决。

RLock对象

该对象可对共享数据进行重复加锁和解锁,只要配对就可以了。

使用方法也很简单,acquire()方法和release()方法之间的就是临界区,在临界区内操作共享数据就是了。

RLock.acquire(blocking=True)

当blocking设置为true时,在加锁状态,其它线程A想获得锁,则A线程会被阻塞,直到解锁返回为True。

当blocking设置为true时,在加锁状态,其它线程A想获得锁,则A线程不会被阻塞,直接返回False。

RLock.release()

解锁,无返回值。

Condition对象

个人认为Condition对象,是对Lock对象的一种再封装。你可以传给它一个已有的锁对象,如果未指定,则自行创建一个锁。

threading.Condition(lock=None)

默认为None,可传给它一个Lock或者RLock对象。

acquire(*args)

获得潜在的锁。说白了,就是调用潜在锁对象的acquire()方法,人家返回啥,它也就返回啥了。

release()

释放潜在锁,没有返回值。

wait(timeout=None)

等待直到被唤醒或者timeout时间到。如果调用者并未获得锁而执行此方法,则会抛出RuntimeError异常。

这个方法会释放锁,然后睡眠直到在其它线程被同一condition变量的notify()或者notify_all()方法唤醒,或者timeout时间到。如果被唤醒,它将重新获得锁。

notify()

唤醒在这个condition对象上睡眠的一个线程,如果有的话。如果没有获得锁而调用此方法,则会抛出RuntimeError异常。

该方法会唤醒一个线程,如果没有线程在睡眠,该方法不做其它操作。

记住:notify()方法并没有释放锁,所以,还得你自己亲力亲为哦。

notify_all()

方法与notify()类似,不过是唤醒所有睡眠线程。

 

Event对象

这个对象用来进行进程间的简单通信。上面的Condition对象来RLock对象用来对共享数据进行操作,当然,在一定程度上,也实现了线程间的通信。但二者的侧重点是不一样的。Event并没有涉及共享数据的操作。

class threading.Event

is_set()

返回为True如果内部标志已经被设置为True的话。

set()

设置内部标志为True。线程在内部标志为true时才会被唤醒。如果内部标志被设置为true,又调用wait()方法,则不会睡眠。

clear()

设置内部标志为false。

wait(timeout=None)

在内部标志为false时,进入睡眠状态,直到该标志被设置为true时才会被唤醒。

 

Timer对象

周期性执行某任务的类。直接以例子来说话吧。

def hello():

   print("hello, s")

obj = Timer(30.0, hello)

t.start()

 

#t.cancel()

 

2:例子

其实自我感觉Python的多线程很类似于Java的多线程机制,但是比JAVA的多线程更灵活。在早期的Python多线程实现中,采用了thread模块。例如:   

   

# -*- coding: utf-8 -*-
from time import ctime,sleep  
from thread import start_new_thread  
def loop1():  
    print "进入 方法1:",ctime();  
    sleep(3);  
    print "退出 方法1:",ctime();  
  
def loop2():  
    print "进入 方法2:",ctime();  
    sleep(5);  
    print "退出 方法2:",ctime();  
  
def main():  
    print "main begin:",ctime();  
    start_new_thread(loop1, ());  
    start_new_thread(loop2,());  
    sleep(9);  
    print "main end:",ctime();  
  
if __name__=="__main__":  
    main();

 显示:

 

main begin: Mon Dec 23 16:45:19 2013
进入 方法1: Mon Dec 23 16:45:19 2013
进入 方法2: Mon Dec 23 16:45:19 2013
退出 方法1: Mon Dec 23 16:45:22 2013
退出 方法2: Mon Dec 23 16:45:24 2013
main end: Mon Dec 23 16:45:28 2013
[Finished in 9.2s]

 

    简单介绍下这个代码块中的函数功能,sleep是线程睡眠时间,几乎等价于JAVA中的Thread.sleep(millionseconds)

    start_new_thread是实例化一个线程并运行的方法,方法的第一个参数接受一个线程运行时所执行的函数对象,第二个参数是方法执行时所需要的参数,以一个元组的形式传入。   

    这大概是最早期的Python多线程实现了,注意代码中的main线程里的sleep(8)。这里的睡眠时间只能比3+5大,而不能小。如果小于这个时间,那么main主线程会提前退出,导致无论其子线程是否是后台线程,都将会中断,从而抛出线程中断异常,类似于Java的ThreadInterruptException。这个致命的影响几乎就是这个模块后期被抛弃的罪魁祸首。

    当然在早期的Python多线程中,你可以利用加锁的机制来避免出现这个情况。稍微改动下以上代码:

    

Python代码   收藏代码
  1. import thread;  
  2. from time import sleep,ctime;  
  3. from random import choice  
  4. #The first param means the thread number  
  5. #The second param means how long it sleep  
  6. #The third param means the Lock  
  7. def loop(nloop,sec,lock):  
  8.     print "Thread ",nloop," start and will sleep ",sec;  
  9.     sleep(sec);  
  10.     print "Thread ",nloop," end  ",sec;  
  11.     lock.release();  
  12.   
  13. def main():  
  14.     seconds=[4,2];  
  15.     locks=[];  
  16.     for i in range(len(seconds)) :  
  17.         lock=thread.allocate_lock();  
  18.         lock.acquire();  
  19.         locks.append(lock);  
  20.           
  21.     print "main Thread begins:",ctime();  
  22.     for i,lock in enumerate(locks):  
  23.         thread.start_new_thread(loop,(i,choice(seconds),lock));  
  24.     for lock in locks :  
  25.         while lock.locked() :   
  26.             pass;  
  27.     print "main Thread ends:",ctime();  
  28.   
  29. if __name__=="__main__" :  
  30.     main();  

 

 

 

 

    这里对Python线程运行时加入了锁监控机制,介绍下红色字体标志的几个方法(其实红色字体中的lock实质是thread.lockType实例。 ):

    从以上介绍可以看出这个Lock类非常类似于JDK5.0中的java.util.concurrent.locks.Lock。不知道Doug Lea有没有参与这个模块的开发,哈哈~~(纯属YY),只是比JAVA中的LOCK类多了一个方法locked,用于检测Lock对象是否还处于加锁的状态。

    所以上一个例子的工作原理就是在启动线程的时候,给每个线程都加了一把锁,直到线程运行介绍,再释放这个锁。同时在Python的main线程中用一个while循环来不停的判断每个线程锁已释放。这个方法虽然避免了最开始的例子中人为的时间控制,但是还不方便,高效。

    所以在较新的Python版本中,都推荐使用threading模块。

    看下threading模块的API,有过JAVA开发经验的会发现它和java.lang.Thread类非常接近。这里需要说的一点就是threading的run方法可以返回函数值,这点在用于跟踪和判断线程运行正常与否非常有作用。

   threading模块支持三种方法来创建线程。而前两种方式都与其Thread类有关。看下它的简要说明:

 

    

Python代码   收藏代码
  1. class Thread(_Verbose) :  
  2.      __init__(self, group=None, target=None, name=None, args=(), kwargs=None, verbose=None)  

 

 

 

 

 

 

   其中target指的是一个具体的函数,或者可调用的类实例(这里指实现了__call__方法的类实例) 

  第一种方法:指定线程运行的时候调用的函数。举例如下:

 

 

Python代码   收藏代码
  1. from time import ctime,sleep  
  2. import threading;  
  3. from random import choice  
  4.   
  5. def loop(number,sec):  
  6.     print "Thread ",number," begins and will sleep ",sec," at ",ctime();  
  7.     sleep(sec);  
  8.     print "Thread ",number,"ends at ",ctime();  
  9.       
  10. def main():  
  11.     seconds=[2,4];  
  12.     threads=[];  
  13.     array=range(len(seconds));  
  14.     for i in array :  
  15.         t=threading.Thread(target=loop,args=(i,choice(seconds)));  
  16.         threads.append(t);  
  17.     print "main Thread begins at ",ctime();  
  18.     for t in threads :  
  19.         t.start();  
  20.     for t in threads :  
  21.         t.join();          
  22.     print "main Thread ends at ",ctime();  
  23.   
  24. if __name__=="__main__" :  
  25.     main();  

 

 

 

 

    从图上可以看出,这里target指向了一个具体的函数对象,而args传入了该方法调用时所必须的参数。这里传入了一个随即的睡眠时间。其中thread.join表示要等待该线程终止,和java中的Thread.join(long millionseconds)作用一样,如果不指定具体的时间的话,将会一直等待下去。

 

 

   

   第二种方法就是指定一个可调用的类实例,实际上与前面一种非常的接近。如下所示:

  

Python代码   收藏代码
  1. from time import ctime,sleep  
  2. import threading;  
  3. from random import choice  
  4.   
  5. class ThreadFunc(object):  
  6.     def __init__(self,func,args,name):  
  7.         self.func=func;  
  8.         self.args=args;  
  9.         self.name=name;  
  10.           
  11.     def __call__(self):  
  12.         self.func(*self.args);  
  13.   
  14. def loop(number,sec):  
  15.     print "Thread ",number," begins and will sleep ",sec," at ",ctime();  
  16.     sleep(sec);  
  17.     print "Thread ",number,"ends at ",ctime();  
  18.       
  19. def main():  
  20.     seconds=[2,4];  
  21.     threads=[];  
  22.     array=range(len(seconds));  
  23.     for i in array :  
  24.         t=threading.Thread(target=ThreadFunc(loop,(i,choice(seconds)),loop.__name__));  
  25.         threads.append(t);  
  26.     print "main Thread begins at ",ctime();  
  27.     for t in threads :  
  28.         t.start();  
  29.     for t in threads :  
  30.         t.join();          
  31.     print "main Thread ends at ",ctime();  
  32.   
  33. if __name__=="__main__" :  
  34.     main();  

 

 

 

 

   这里只是将target指向从一个函数对象变成了一个可调用的类实例。

 

    重点推荐下第三种方式,用继承threading.Thread的方式来实现线程,有过Java多线程应用的朋友一定会对下面的例子非常熟悉。

   

Python代码   收藏代码
  1. from time import ctime,sleep  
  2. import threading;  
  3. from random import choice  
  4.   
  5. class MyThread(threading.Thread):  
  6.     def __init__(self,func,args,name):  
  7.         super(MyThread,self).__init__();  
  8.         self.func=func;  
  9.         self.args=args;  
  10.         self.name=name;  
  11.               
  12.     def run(self):  
  13.         self.result=self.func(*self.args);  
  14.   
  15.     def getResult(self):  
  16.         return self.result;  
  17.       
  18. def loop(number,sec):  
  19.     print "Thread ",number," begins and will sleep ",sec," at ",ctime();  
  20.     sleep(sec);  
  21.     print "Thread ",number,"ends at ",ctime();  
  22.       
  23. def main():  
  24.     seconds=[2,4];  
  25.     threads=[];  
  26.     array=range(len(seconds));  
  27.     for i in array :  
  28.         t=MyThread(loop,(i,choice(seconds)),loop.__name__);  
  29.         threads.append(t);  
  30.     print "main Thread begins at ",ctime();  
  31.     for t in threads :  
  32.         t.start();  
  33.     for t in threads :  
  34.         t.join();          
  35.     print "main Thread ends at ",ctime();  
  36.   
  37. if __name__=="__main__" :  
  38.     main();  

 

 

 

 

    

    从上面可以看出MyThread继承了threading.Thread类,并在初始化方法中执行了必要的参数赋值。值得注意的是在Java类的继承中,如果不显示的指定调用父类的构造方法,那么默认将调用父类的无参构造方法。而在Python中,就不会主动去调用。所以这里需要显示的调用父类的初始化方法。

 

3:线程间返回值汇总

# -*- coding:utf-8 -*-
import threading
class MyThread(object):
    def __init__(self, func_list=None):
    #所有线程函数的返回值汇总,如果最后为0,说明全部成功
        self.ret_flag = 0
        self.func_list = func_list
        self.threads = []
         
    def set_thread_func_list(self, func_list):
        """
        @note: func_list是一个list,每个元素是一个dict,有func和args两个参数
        """
        self.func_list = func_list

 
    def ret_value(self):
        """
        @note: 所有线程函数的返回值之和,如果为0那么表示所有函数执行成功
        """
        return self.ret_flag

    def trace_func(self, func, *args, **kwargs):
        """
        @note:替代profile_func,新的跟踪线程返回值的函数,对真正执行的线程函数包一次函数,以获取返回值
        """
        ret = func(*args, **kwargs)
        self.ret_flag += ret



    def start(self):
        """
        @note: 启动多线程执行,并阻塞到结束
        """
        self.threads = []
        self.ret_flag = 0
        for func_dict in self.func_list:
            if func_dict["args"]:
                new_arg_list = []
                new_arg_list.append(func_dict["func"])
                for arg in func_dict["args"]:
                    new_arg_list.append(arg)
                new_arg_tuple = tuple(new_arg_list)
                t = threading.Thread(target=self.trace_func, args=new_arg_tuple)
            else:
                t = threading.Thread(target=self.trace_func, args=(func_dict["func"],))
            self.threads.append(t)
     
        for thread_obj in self.threads:
            thread_obj.start()
     
        for thread_obj in self.threads:
            thread_obj.join()
def func1(ret_num):
    print "func1 ret:%d" % ret_num
    return ret_num
 
def func2(ret_num):
    print "func2 ret:%d" % ret_num
    return ret_num
 
def func3():
    print "func3 ret:100"
    return 100
 
mt = MyThread()
g_func_list = []
g_func_list.append({"func":func1,"args":(1,)})
g_func_list.append({"func":func2,"args":(2,)})
g_func_list.append({"func":func3,"args":None})
mt.set_thread_func_list(g_func_list)
mt.start()
print "all thread ret : %d" % mt.ret_flag

 

分享到:
评论

相关推荐

    office文档通过openoffice或者microsoft多线程转换成pdf文档并通过pdfjs显示

    标题提到的"office文档通过openoffice或者microsoft多线程转换成pdf文档"涉及到的技术主要包括办公软件API接口利用、多线程处理以及文件转换技术。首先,OpenOffice和Microsoft Office都提供了能够读取和操作Office...

    springboot 文件转换PDF多线程

    根据网上的资料总结的一个springboot 转换pdf Word文档大小最好2m以下 需要安装OpenOffice.org 3.3 链接:https://pan.baidu.com/s/1onrkhBCNlGLEmf3hPwzXWw 密码:8h5a

    批量、多线程转换网易云音乐ncm文件到mp3flac的linux命令行工具_ncm2dump.zip

    批量、多线程转换网易云音乐ncm文件到mp3flac的linux命令行工具_ncm2dump

    pdf2word,60行代码实现多线程PDF转Word

    【标题】"pdf2word,60行代码实现多线程PDF转Word"涉及的核心知识点是使用Python编程语言进行PDF到Word的转换,并且利用多线程技术提高转换效率。在Python中,处理这种文件格式转换通常需要借助特定的库,如PyPDF2...

    C# 多线程控制实例

    在C#编程中,多线程技术是一种关键的并发处理机制,它允许程序同时执行多个独立的任务,从而提高应用程序的效率和响应性。本实例主要探讨如何在C#中创建和控制多线程,包括线程的启动、挂起和停止。 首先,要创建一...

    根据mysql数据库里图片路径 多线程旋转图片

    在本场景中,任务是根据MySQL数据库中存储的图片路径,使用多线程来批量旋转这些图片。这涉及到两个关键知识点:1) 图像处理(以Bitmap为例)和2) 多线程编程。 首先,让我们详细了解一下`Bitmap`。Bitmap是Android...

    Arduino 使用多线程例子

    标题中的“Arduino 使用多线程例子”意味着我们将探讨如何在Arduino平台上实现多任务并行处理。通常,Arduino基于单片机,不直接支持操作系统或内置的多线程机制。但是,通过巧妙编程和使用库,我们可以模拟多线程的...

    C#泛型参数多线程与复杂参数多线程2

    最近用多线程用的比较多自己走了一些弯路,分享出来希望大家少走弯路,C#中的多线程有两个重载,一个是不带参数的,一个是带参数的,但是即便是带参数的多线程也不支持泛型,这使得使用泛型参数多线程的时候很不方便...

    PB多线程实现

    本文将详细探讨PB(包括PB9、PB12.5以及PB.NET)实现多线程的方法。 一、PB9的多线程实现 在PB9中,虽然官方并未直接支持多线程,但开发者可以通过使用Windows API函数来实现。一种常见的方式是创建一个新的窗口类...

    多线程基础与基于多线程的简单聊天室

    在IT行业中,多线程是程序设计中的一个重要概念,尤其在Java编程中,它被广泛应用于提高应用程序的并发性能和响应速度。本压缩包“多线程基础与基于多线程的简单聊天室”提供了对多线程技术的实践理解和二次开发的...

    delphi多线程调用dll

    在Delphi编程中,多线程技术被广泛用于提高应用程序的执行效率,特别是在处理大量数据或执行长时间操作时。DLL(动态链接库)是Windows操作系统中的一个重要组件,它允许代码和资源在多个程序之间共享。当需要在多...

    稳定、方便、实用的VB6多线程技术(附老马的ActiveX多线程示例)

    多线程技术是现代软件开发中的重要概念,它允许程序同时执行多个任务,从而提高效率和响应性。VB6虽然相对老旧,但其支持的多线程功能依然具有实用性,尤其是在处理耗时操作或需要并发执行任务的应用场景。 VB6中的...

    java 多线程操作数据库

    ### Java多线程操作数据库:深入解析与应用 在当今高度并发的应用环境中,Java多线程技术被广泛应用于处理数据库操作,以提升系统的响应速度和处理能力。本文将基于一个具体的Java多线程操作数据库的应用程序,深入...

    多线程发邮件

    在IT行业中,多线程技术是一项重要的编程技巧,特别是在处理并发任务时,它能显著提升程序的执行效率。本示例“多线程发邮件”就是利用了这一特性,通过并发执行多个邮件发送任务,来加快邮件的发送速度。下面我们将...

    多线程面试题

    在Java编程领域,多线程是面试中常见且重要的知识点,尤其对于系统设计和高并发处理的岗位至关重要。本文将围绕“多线程面试题”这一主题,深入探讨相关概念、技术及其应用。 1. **线程的概念**:线程是程序执行的...

    FFmpegH264 多线程 优化

    本项目专注于FFmpeg中的H264解码库,通过引入多线程和硬件加速技术如MMX、SSE(Streaming SIMD Extensions)和AVX(Advanced Vector Extensions),来提升解码性能和效率。 多线程技术在FFmpeg中的应用主要是为了...

    vb模拟多线程 本地Timer对多线程

    在VB(Visual Basic)编程环境中,由于其原生特性不直接支持多线程,开发者往往需要借助外部API(应用程序接口)来实现多线程功能。标题提到的“vb模拟多线程 本地Timer对多线程”就是一种常见的解决策略,通过使用...

    java实现多线程文件传输

    在Java编程语言中,实现多线程文件传输是一种优化程序性能、提高系统资源利用率的有效方法。多线程允许我们同时处理多个任务,这对于大文件传输或需要并行处理的场景尤其有用。本篇文章将深入探讨如何使用Java实现多...

Global site tag (gtag.js) - Google Analytics