设置线程名称
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();
显示:
进入 方法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多线程中,你可以利用加锁的机制来避免出现这个情况。稍微改动下以上代码:
- import thread;
- from time import sleep,ctime;
- from random import choice
- #The first param means the thread number
- #The second param means how long it sleep
- #The third param means the Lock
- def loop(nloop,sec,lock):
- print "Thread ",nloop," start and will sleep ",sec;
- sleep(sec);
- print "Thread ",nloop," end ",sec;
- lock.release();
- def main():
- seconds=[4,2];
- locks=[];
- for i in range(len(seconds)) :
- lock=thread.allocate_lock();
- lock.acquire();
- locks.append(lock);
- print "main Thread begins:",ctime();
- for i,lock in enumerate(locks):
- thread.start_new_thread(loop,(i,choice(seconds),lock));
- for lock in locks :
- while lock.locked() :
- pass;
- print "main Thread ends:",ctime();
- if __name__=="__main__" :
- 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类有关。看下它的简要说明:
- class Thread(_Verbose) :
- __init__(self, group=None, target=None, name=None, args=(), kwargs=None, verbose=None)
其中target指的是一个具体的函数,或者可调用的类实例(这里指实现了__call__方法的类实例)
第一种方法:指定线程运行的时候调用的函数。举例如下:
- from time import ctime,sleep
- import threading;
- from random import choice
- def loop(number,sec):
- print "Thread ",number," begins and will sleep ",sec," at ",ctime();
- sleep(sec);
- print "Thread ",number,"ends at ",ctime();
- def main():
- seconds=[2,4];
- threads=[];
- array=range(len(seconds));
- for i in array :
- t=threading.Thread(target=loop,args=(i,choice(seconds)));
- threads.append(t);
- print "main Thread begins at ",ctime();
- for t in threads :
- t.start();
- for t in threads :
- t.join();
- print "main Thread ends at ",ctime();
- if __name__=="__main__" :
- main();
从图上可以看出,这里target指向了一个具体的函数对象,而args传入了该方法调用时所必须的参数。这里传入了一个随即的睡眠时间。其中thread.join表示要等待该线程终止,和java中的Thread.join(long millionseconds)作用一样,如果不指定具体的时间的话,将会一直等待下去。
第二种方法就是指定一个可调用的类实例,实际上与前面一种非常的接近。如下所示:
- from time import ctime,sleep
- import threading;
- from random import choice
- class ThreadFunc(object):
- def __init__(self,func,args,name):
- self.func=func;
- self.args=args;
- self.name=name;
- def __call__(self):
- self.func(*self.args);
- def loop(number,sec):
- print "Thread ",number," begins and will sleep ",sec," at ",ctime();
- sleep(sec);
- print "Thread ",number,"ends at ",ctime();
- def main():
- seconds=[2,4];
- threads=[];
- array=range(len(seconds));
- for i in array :
- t=threading.Thread(target=ThreadFunc(loop,(i,choice(seconds)),loop.__name__));
- threads.append(t);
- print "main Thread begins at ",ctime();
- for t in threads :
- t.start();
- for t in threads :
- t.join();
- print "main Thread ends at ",ctime();
- if __name__=="__main__" :
- main();
这里只是将target指向从一个函数对象变成了一个可调用的类实例。
重点推荐下第三种方式,用继承threading.Thread的方式来实现线程,有过Java多线程应用的朋友一定会对下面的例子非常熟悉。
- from time import ctime,sleep
- import threading;
- from random import choice
- class MyThread(threading.Thread):
- def __init__(self,func,args,name):
- super(MyThread,self).__init__();
- self.func=func;
- self.args=args;
- self.name=name;
- def run(self):
- self.result=self.func(*self.args);
- def getResult(self):
- return self.result;
- def loop(number,sec):
- print "Thread ",number," begins and will sleep ",sec," at ",ctime();
- sleep(sec);
- print "Thread ",number,"ends at ",ctime();
- def main():
- seconds=[2,4];
- threads=[];
- array=range(len(seconds));
- for i in array :
- t=MyThread(loop,(i,choice(seconds)),loop.__name__);
- threads.append(t);
- print "main Thread begins at ",ctime();
- for t in threads :
- t.start();
- for t in threads :
- t.join();
- print "main Thread ends at ",ctime();
- if __name__=="__main__" :
- 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文档"涉及到的技术主要包括办公软件API接口利用、多线程处理以及文件转换技术。首先,OpenOffice和Microsoft Office都提供了能够读取和操作Office...
根据网上的资料总结的一个springboot 转换pdf Word文档大小最好2m以下 需要安装OpenOffice.org 3.3 链接:https://pan.baidu.com/s/1onrkhBCNlGLEmf3hPwzXWw 密码:8h5a
批量、多线程转换网易云音乐ncm文件到mp3flac的linux命令行工具_ncm2dump
【标题】"pdf2word,60行代码实现多线程PDF转Word"涉及的核心知识点是使用Python编程语言进行PDF到Word的转换,并且利用多线程技术提高转换效率。在Python中,处理这种文件格式转换通常需要借助特定的库,如PyPDF2...
在C#编程中,多线程技术是一种关键的并发处理机制,它允许程序同时执行多个独立的任务,从而提高应用程序的效率和响应性。本实例主要探讨如何在C#中创建和控制多线程,包括线程的启动、挂起和停止。 首先,要创建一...
在本场景中,任务是根据MySQL数据库中存储的图片路径,使用多线程来批量旋转这些图片。这涉及到两个关键知识点:1) 图像处理(以Bitmap为例)和2) 多线程编程。 首先,让我们详细了解一下`Bitmap`。Bitmap是Android...
标题中的“Arduino 使用多线程例子”意味着我们将探讨如何在Arduino平台上实现多任务并行处理。通常,Arduino基于单片机,不直接支持操作系统或内置的多线程机制。但是,通过巧妙编程和使用库,我们可以模拟多线程的...
最近用多线程用的比较多自己走了一些弯路,分享出来希望大家少走弯路,C#中的多线程有两个重载,一个是不带参数的,一个是带参数的,但是即便是带参数的多线程也不支持泛型,这使得使用泛型参数多线程的时候很不方便...
本文将详细探讨PB(包括PB9、PB12.5以及PB.NET)实现多线程的方法。 一、PB9的多线程实现 在PB9中,虽然官方并未直接支持多线程,但开发者可以通过使用Windows API函数来实现。一种常见的方式是创建一个新的窗口类...
在IT行业中,多线程是程序设计中的一个重要概念,尤其在Java编程中,它被广泛应用于提高应用程序的并发性能和响应速度。本压缩包“多线程基础与基于多线程的简单聊天室”提供了对多线程技术的实践理解和二次开发的...
在Delphi编程中,多线程技术被广泛用于提高应用程序的执行效率,特别是在处理大量数据或执行长时间操作时。DLL(动态链接库)是Windows操作系统中的一个重要组件,它允许代码和资源在多个程序之间共享。当需要在多...
多线程技术是现代软件开发中的重要概念,它允许程序同时执行多个任务,从而提高效率和响应性。VB6虽然相对老旧,但其支持的多线程功能依然具有实用性,尤其是在处理耗时操作或需要并发执行任务的应用场景。 VB6中的...
### Java多线程操作数据库:深入解析与应用 在当今高度并发的应用环境中,Java多线程技术被广泛应用于处理数据库操作,以提升系统的响应速度和处理能力。本文将基于一个具体的Java多线程操作数据库的应用程序,深入...
在IT行业中,多线程技术是一项重要的编程技巧,特别是在处理并发任务时,它能显著提升程序的执行效率。本示例“多线程发邮件”就是利用了这一特性,通过并发执行多个邮件发送任务,来加快邮件的发送速度。下面我们将...
在Java编程领域,多线程是面试中常见且重要的知识点,尤其对于系统设计和高并发处理的岗位至关重要。本文将围绕“多线程面试题”这一主题,深入探讨相关概念、技术及其应用。 1. **线程的概念**:线程是程序执行的...
本项目专注于FFmpeg中的H264解码库,通过引入多线程和硬件加速技术如MMX、SSE(Streaming SIMD Extensions)和AVX(Advanced Vector Extensions),来提升解码性能和效率。 多线程技术在FFmpeg中的应用主要是为了...
在VB(Visual Basic)编程环境中,由于其原生特性不直接支持多线程,开发者往往需要借助外部API(应用程序接口)来实现多线程功能。标题提到的“vb模拟多线程 本地Timer对多线程”就是一种常见的解决策略,通过使用...
在Java编程语言中,实现多线程文件传输是一种优化程序性能、提高系统资源利用率的有效方法。多线程允许我们同时处理多个任务,这对于大文件传输或需要并行处理的场景尤其有用。本篇文章将深入探讨如何使用Java实现多...