Python多线程与多进程及其区别

个人一直觉得对学习任何知识而言,概念是相当重要的。掌握了概念和原理,细节可以留给实践去推敲。掌握的关键在于理解,通过具体的实例和实际操作来感性的体会概念和原理可以起到很好的效果。本文通过一些具体的例子简单介绍一下Python的多线程和多进程,后续会写一些进程通信和线程通信的一些文章。

python多线程

python中提供两个标准库thread和threading用于对线程的支持,python3中已放弃对前者的支持,后者是一种更高层次封装的线程库,接下来均以后者为例。

创建线程

python中有两种方式实现线程:

实例化一个threading.Thread的对象,并传入一个初始化函数对象(initial function )作为线程执行的入口;

继承threading.Thread,并重写run函数;

方式1:创建threading.Thread对象

import threading import time def tstart(arg): time.sleep(0.5) print("%s running...." % arg) if __name__ == '__main__': t1 = threading.Thread(target=tstart, args=('This is thread 1',)) t2 = threading.Thread(target=tstart, args=('This is thread 2',)) t1.start() t2.start() print("This is main function")

结果:

This is main function This is thread 2 running.... This is thread 1 running....

View Code

方式2:继承threading.Thread,并重写run

import threading import time class CustomThread(threading.Thread): def __init__(self, thread_name): # step 1: call base __init__ function super(CustomThread, self).__init__(name=thread_name) self._tname = thread_name def run(self): # step 2: overide run function time.sleep(0.5) print("This is %s running...." % self._tname) if __name__ == "__main__": t1 = CustomThread("thread 1") t2 = CustomThread("thread 2") t1.start() t2.start() print("This is main function")

执行结果同方式1.

threading.Thread

上面两种方法本质上都是直接或者间接使用threading.Thread类

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

关联上面两种创建线程的方式:

import threading import time class CustomThread(threading.Thread): def __init__(self, thread_name, target = None): # step 1: call base __init__ function super(CustomThread, self).__init__(name=thread_name, target=target, args = (thread_name,)) self._tname = thread_name def run(self): # step 2: overide run function # time.sleep(0.5) # print("This is %s running....@run" % self._tname) super(CustomThread, self).run() def target(arg): time.sleep(0.5) print("This is %s running....@target" % arg) if __name__ == "__main__": t1 = CustomThread("thread 1", target) t2 = CustomThread("thread 2", target) t1.start() t2.start() print("This is main function")

结果:

This is main function This is thread 1 running....@target This is thread 2 running....@target

上面这段代码说明:

两种方式创建线程,指定的参数最终都会传给threading.Thread类;

传给线程的目标函数是在基类Thread的run函数体中被调用的,如果run没有被重写的话。

threading模块的一些属性和方法可以参照官网,这里重点介绍一下threading.Thread对象的方法

下面是threading.Thread提供的线程对象方法和属性:

start():创建线程后通过start启动线程,等待CPU调度,为run函数执行做准备;

run():线程开始执行的入口函数,函数体中会调用用户编写的target函数,或者执行被重载的run函数;

join([timeout]):阻塞挂起调用该函数的线程,直到被调用线程执行完成或超时。通常会在主线程中调用该方法,等待其他线程执行完成。

name、getName()&setName():线程名称相关的操作;

ident:整数类型的线程标识符,线程开始执行前(调用start之前)为None;

isAlive()、is_alive():start函数执行之后到run函数执行完之前都为True;

daemon、isDaemon()&setDaemon():守护线程相关;

这些是我们创建线程之后通过线程对象对线程进行管理和获取线程信息的方法。

 多线程执行

在主线程中创建若线程之后,他们之间没有任何协作和同步,除主线程之外每个线程都是从run开始被执行,直到执行完毕。

join

我们可以通过join方法让主线程阻塞,等待其创建的线程执行完成。

import threading import time def tstart(arg): print("%s running....at: %s" % (arg,time.time())) time.sleep(1) print("%s is finished! at: %s" % (arg,time.time())) if __name__ == '__main__': t1 = threading.Thread(target=tstart, args=('This is thread 1',)) t1.start() t1.join() # 当前线程阻塞,等待t1线程执行完成 print("This is main function at:%s" % time.time())

结果:

This is thread 1 running....at: 1564906617.43 This is thread 1 is finished! at: 1564906618.43 This is main function at:1564906618.43

如果不加任何限制,当主线程执行完毕之后,当前程序并不会结束,必须等到所有线程都结束之后才能结束当前进程。

将上面程序中的t1.join()去掉,执行结果如下:

This is thread 1 running....at: 1564906769.52 This is main function at:1564906769.52 This is thread 1 is finished! at: 1564906770.52

可以通过将创建的线程指定为守护线程(daemon),这样主线程执行完毕之后会立即结束未执行完的线程,然后结束程序。

deamon守护线程

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/8abfe932db5ef9cdd61f376dbdc00883.html