在本章中,我们将学习如何在Python中实现线程。
Python线程有时称为轻量级进程,因为线程比进程占用的内存少得多。 线程允许一次执行多个任务。 在Python中,以下两个模块在一个程序中实现线程 -
_thread
模块threading
模块这两个模块之间的主要区别在于_thread
模块将线程视为一个函数,而threading
模块将每个线程视为一个对象并以面向对象的方式实现它。 此外,_thread
模块在低级线程中有效并且比threading
模块具有更少的功能。
在Python的早期版本中,拥有thread
模块,但在相当长的一段时间里它已被视为“已弃用”。 鼓励用户改用threading
模块。 因此,在Python 3中,thread
模块不再可用。 它已被重命名为_thread
,用于Python3中的向后不兼容。
为了在_thread
模块的帮助下生成新的线程,我们需要调用它的start_new_thread
方法。 这种方法的工作可以通过以下语法来理解 -
_thread.start_new_thread ( function, args[, kwargs] )
这里,
args
是一个参数的元组kwargs
是关键字参数的可选字典如果想在不传递参数的情况下调用函数,那么需要在args
中使用一个空的参数元组。
此方法调用立即返回,子线程启动,并调用与传递的列表(如果有的话)args
的函数。 线程在函数返回时终止。
示例
以下是使用_thread
模块生成新线程的示例。在这里使用start_new_thread()
方法。
import _thread import time def print_time( threadName, delay): count = 0 while count < 5: time.sleep(delay) count += 1 print ("%s: %s" % ( threadName, time.ctime(time.time()) )) try: _thread.start_new_thread( print_time, ("Thread-1", 2, ) ) _thread.start_new_thread( print_time, ("Thread-2", 4, ) ) except: print ("Error: unable to start thread") while 1: pass
在_thread
模块的帮助下理解新线程的生成。
Thread-1: Mon Apr 23 10:03:33 2018 Thread-2: Mon Apr 23 10:03:35 2018 Thread-1: Mon Apr 23 10:03:35 2018 Thread-1: Mon Apr 23 10:03:37 2018 Thread-2: Mon Apr 23 10:03:39 2018 Thread-1: Mon Apr 23 10:03:39 2018 Thread-1: Mon Apr 23 10:03:41 2018 Thread-2: Mon Apr 23 10:03:43 2018 Thread-2: Mon Apr 23 10:03:47 2018 Thread-2: Mon Apr 23 10:03:51 2018
threading
模块以面向对象的方式实现,并将每个线程视为一个对象。 因此,它为线程提供了比_thread
模块更强大,更高层次的支持。该模块包含在Python 2.4中。
threading
模块包含_thread
模块的所有方法,但它也提供了其他方法。 其他方法如下 -
threading.activeCount()
- 此方法返回处于活动状态的线程对象的数量threading.currentThread()
- 此方法返回调用者线程控制中的线程对象数。threading.enumerate()
- 此方法返回当前活动的所有线程对象的列表。为了实现线程,threading
模块具有提供以下方法的Thread
类 -
run()
- run()
方法是线程的入口点。start()
- start()
方法通过调用run方法来启动线程。join([time])
- join()
等待线程终止。isAlive()
- isAlive()
方法检查线程是否仍在执行。getName()
- getName()
方法返回线程的名称。setName()
- setName()
方法设置线程的名称。在本节中,我们将学习如何使用threading
模块创建线程。 按照以下步骤使用threading
模块创建一个新线程 -
第1步 - 在这一步中,需要定义Thread
类的新子类。
第2步 - 然后为了添加额外的参数,需要重写__init __(self [,args])
方法。
第3步 - 在这一步中,需要重写run(self [,args])
方法来实现线程在启动时应该执行的操作。
现在,在创建新的Thread
子类后,可以创建它的一个实例,然后通过调用start()
来启动一个新线程,start()
又调用run()
方法。
示例
下面这个例子演示如何使用threading
模块生成一个新的线程。
import threading import time exitFlag = 0 class myThread (threading.Thread): def __init__(self, threadID, name, counter): threading.Thread.__init__(self) self.threadID = threadID self.name = name self.counter = counter def run(self): print ("Starting " + self.name) print_time(self.name, self.counter, 5) print ("Exiting " + self.name) def print_time(threadName, delay, counter): while counter: if exitFlag: threadName.exit() time.sleep(delay) print ("%s: %s" % (threadName, time.ctime(time.time()))) counter -= 1 thread1 = myThread(1, "Thread-1", 1) thread2 = myThread(2, "Thread-2", 2) thread1.start() thread2.start() thread1.join() thread2.join() print ("Exiting Main Thread") Starting Thread-1 Starting Thread-2
执行上面示例代码,得到以下结果 -
Thread-1: Mon Apr 23 10:52:09 2018 Thread-1: Mon Apr 23 10:52:10 2018 Thread-2: Mon Apr 23 10:52:10 2018 Thread-1: Mon Apr 23 10:52:11 2018 Thread-1: Mon Apr 23 10:52:12 2018 Thread-2: Mon Apr 23 10:52:12 2018 Thread-1: Mon Apr 23 10:52:13 2018 Exiting Thread-1 Thread-2: Mon Apr 23 10:52:14 2018 Thread-2: Mon Apr 23 10:52:16 2018 Thread-2: Mon Apr 23 10:52:18 2018 Exiting Thread-2 Exiting Main Thread
有五种线程状态 - 新的,可运行,运行,等待和死亡。 在这五个中,我们将主要关注三个状态 - 运行,等待和死亡。 一个线程获取处于运行状态的资源,等待处于等待状态的资源; 如果执行和获取的资源的最终版本处于死亡状态。
下面的Python程序在start()
,sleep()
和join()
方法的帮助下将分别显示线程是如何进入运行,等待和死亡状态的。
第1步 - 导入必要的模块,threading
和time
import threading import time
第2步 - 定义一个函数,它将在创建线程时调用。
def thread_states(): print("Thread entered in running state")
第3步 - 使用time
模块的sleep()
方法让线程等待2秒钟。
time.sleep(2)
第4步 - 现在,创建一个名为T1
的线程,它接受上面定义的函数的参数。
T1 = threading.Thread(target=thread_states)
第5步 - 现在,使用start()
函数,可以开始启动线程。 它会产生这个信息,这个信息是在定义函数时设定的。
T1.start() # Thread entered in running state
第6步 - 现在,最后可以在完成执行后使用join()
方法终止线程。
T1.join()
在python中,可以通过不同的方式启动一个新的线程,但其中最简单的一个就是将其定义为一个单一的函数。 在定义函数之后,可以将它作为新线程的目标。线程对象等等。 执行下面的Python代码来理解函数的工作原理 -
import threading import time import random def Thread_execution(i): print("Execution of Thread {} started\n".format(i)) sleepTime = random.randint(1,4) time.sleep(sleepTime) print("Execution of Thread {} finished".format(i)) for i in range(4): thread = threading.Thread(target=Thread_execution, args=(i,)) thread.start() print("Active Threads:" , threading.enumerate())
执行上面代码,得到以下结果 -
Execution of Thread 0 started Active Threads: [<_MainThread(MainThread, started 6040)>, <HistorySavingThread(IPythonHistorySavingThread, started 5968)>, <Thread(Thread-3576, started 3932)>] Execution of Thread 1 started Active Threads: [<_MainThread(MainThread, started 6040)>, <HistorySavingThread(IPythonHistorySavingThread, started 5968)>, <Thread(Thread-3576, started 3932)>, <Thread(Thread-3577, started 3080)>] Execution of Thread 2 started Active Threads: [<_MainThread(MainThread, started 6040)>, <HistorySavingThread(IPythonHistorySavingThread, started 5968)>, <Thread(Thread-3576, started 3932)>, <Thread(Thread-3577, started 3080)>, <Thread(Thread-3578, started 2268)>] Execution of Thread 3 started Active Threads: [<_MainThread(MainThread, started 6040)>, <HistorySavingThread(IPythonHistorySavingThread, started 5968)>, <Thread(Thread-3576, started 3932)>, <Thread(Thread-3577, started 3080)>, <Thread(Thread-3578, started 2268)>, <Thread(Thread-3579, started 4520)>] Execution of Thread 0 finished Execution of Thread 1 finished Execution of Thread 2 finished Execution of Thread 3 finished
在python中,可以通过不同的方式启动一个新的线程,但最简单的就是将其定义为一个单一的函数。 在定义函数之后,可以将它作为新线程的目标。线程对象等等。 执行下面的Python代码来理解函数的工作原理 -
import threading import time def nondaemonThread(): print("starting my thread") time.sleep(8) print("ending my thread") def daemonThread(): while True: print("Hello") time.sleep(2) if __name__ == '__main__': nondaemonThread = threading.Thread(target = nondaemonThread) daemonThread = threading.Thread(target = daemonThread) daemonThread.setDaemon(True) daemonThread.start() nondaemonThread.start()
在上面的代码中,有两个函数,分别是- nondaemonThread()
和daemonThread()
。 第一个函数打印其状态并在8秒后休眠,而deamonThread()
函数每2秒无限期地打印出Hello。 我们可以通过以下输出来了解nondaemon
和daemon
线程之间的区别 -
Hello starting my thread Hello Hello Hello Hello ending my thread Hello Hello Hello Hello Hello