什么是线程
线程(Thread)也叫轻量级进程,是操作系统能够进行运算调度的最小单位,它被包涵在进程之中,是进程中的实际运作单位。线程自己不拥有系统资源,只拥有一点儿在运行中必不可少的资源,但它可与同属一个进程的其它线程共享进程所拥有的全部资源。一个线程可以创建和撤消另一个线程,同一进程中的多个线程之间可以并发执行。
为什么要使用多线程
线程在程序中是独立的、并发的执行流。与分隔的进程相比,进程中线程之间的隔离程度要小,它们共享内存、文件句柄和其他进程应有的状态。
因为线程的划分尺度小于进程,使得多线程程序的并发性高。进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率。
线程比进程具有更高的性能,这是由于同一个进程中的线程都有共性多个线程共享同一个进程的虚拟空间。线程共享的环境包括进程代码段、进程的公有数据等,利用这些共享的数据,线程之间很容易实现通信。
操作系统在创建进程时,必须为该进程分配独立的内存空间,并分配大量的相关资源,但创建线程则简单得多。因此,使用多线程来实现并发比使用多进程的性能要高得多。
总结起来,使用多线程编程具有如下几个优点:
- 进程之间不能共享内存,但线程之间共享内存非常容易。
- 操作系统在创建进程时,需要为该进程重新分配系统资源,但创建线程的代价则小得多。因此,使用多线程来实现多任务并发执行比使用多进程的效率高。
- Python 语言内置了多线程功能支持,而不是单纯地作为底层操作系统的调度方式,从而简化了 Python 的多线程编程。
多线程共享全局变量
线程是进程的执行单元,进程是系统分配资源的最小单位,所以在同一个进程中的多线程是共享资源的。
import threading
import time
g_num = 100
def work1():
global g_num
for i in range(3):
g_num += 1
print("in work1 g_num is : %d" % g_num)
def work2():
global g_num
print("in work2 g_num is : %d" % g_num)
if __name__ == '__main__':
t1 = threading.Thread(target=work1)
t1.start()
time.sleep(1)
t2 = threading.Thread(target=work2)
t2.start()
----------------------------------
>>> in work1 g_num is : 103
>>> in work2 g_num is : 103
在创建新线程时,子线程会从其父线程继承其线程属性,主线程是普通的非守护线程,默认情况下,它所创建的任何线程都是非守护线程。本文将介绍Python中的另一类后台线程,守护线程(Daemon Thread)。
参考:https://zhuanlan.zhihu.com/p/81582297
多线程编程当中, 线程的存在形态比较抽象. 通过前台线程\后台线程, 可以有效理解线程运行顺序.(复杂的多线程程序可以通过设置线程优先级实现)
后台线程与前台线程的直接区别是:
1)setDaemon(True): 当主线程退出时,后台线程随机退出;
2)setDaemon(False)(默认情况): 当主线程退出时,若前台线程还未结束,则等待所有线程结束,相当于在程序末尾加入join().
总结
- 如果需要子线程随主线程一同退出-设置它为守护线程。
- 如果需要子线程运行结束后,主线程才能退出-设置子线程为非守护线程。
实例
主线程启动两个子线程:
- 子线程0-守护线程,运行10秒退出
- 子线程1-非守护线程,运行1秒退出。
根据我们上面的总结,我们会知道:
- 主线程启动完子线程,等待所有非守护线程运行
- 非守护子线程1运行1秒退出
- 此时没有非守护线程运行,主线程退出
- 子线程0虽然任务还未完成,但是它是守护线程,会紧跟主线程退出。
import time
import threading
def sub(num):
if i % 2 == 0:
time.sleep(10)
else:
time.sleep(1)
print("thread-{0}: done\n".format(num))
if __name__ == "__main__":
for i in range(2):
t = threading.Thread(target=sub, args=(i, ))
if i % 2 == 0:
t.setDaemon(True)
t.start()
print("thread-{0} started".format(i))
运行结果如下:
thread-0 started
thread-1 started
thread-1: done