3.2.1 线程操作
Posted infinitecodes
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了3.2.1 线程操作相关的知识,希望对你有一定的参考价值。
进程与线程介绍
线程是操作系统能够运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。
从技术性上来说,一段上下文(就是一个线程)由若干CPU寄存器的值组成,
进程与线程不同,一条线程是一段指令上下文。一个进程是一堆与计算有关的资源集合。一个进程可以有一条或多条线程。
注意:与进程有关的资源集合包含内存空间(一个进程中的所有线程共享同一块内存空间),文件描述符(例如:打开的socket链接)和安全认证(如:启动进程的用户的ID)。
进程
一个程序的一个执行实例被称为一个进程。
每个进程提供执行一个程序所需的资源。
一个进程有一个虚拟地址空间,可执行的代码,对操作系统对象开放的接口(句柄),安全认证上下文,一个唯一的进程标识符(PID),环境变量,优先级类,最小与最大的指定的工作空间以及最少执行的一条线程。
每一个进程伴随着一条线程启动,通常被称为主线程,主线程可以通过任何其他线程创建额外的线程。
进程与线程的区别
线程共享一个进程的地址(内存)空间,而进程拥有独立的内存空间。
线程可以直接连接到进程的数据段,而进程则拥有独立的父进程的数据段副本。
同一个进程的线程之间可以直接交流;而多个进程则需要一个中间进程来实现通信。
创建一个新线程很容易;而创建新进程则需要对其父进程进行复制。
线程可以对同一进程里的其他线程进行控制;进程则只能对其子进程进行控制。
对主要线程的改动(取消,优先级变动等)会影响进程中的其他线程的运行;而父进程的改动不会影响子进程。
并发多线程效果演示
示例
import threading import time def run(n): print(‘task:‘, n) before_sleep = time.time() time.sleep(2) after_sleep = time.time() print(after_sleep - before_sleep) t1 = threading.Thread(target=run, args=(‘t1‘, )) #args参数为元组,所以必须加逗号 t2 = threading.Thread(target=run, args=(‘t2‘, )) t1.start() t2.start()
结果
task: t1 task: t2 2.021209478378296 2.021209478378296
看,如果是串行,2个线程应该睡4秒,但这里睡了2秒,成功!
下面是基于类的写法,效果是一样的
import threading import time class MyThread(threading.Thread): def __init__(self, n): super(MyThread, self).__init__() self.n = n def run(self): print(‘task: ‘, self.n) before_sleep = time.time() time.sleep(2) after_sleep = time.time() print(after_sleep - before_sleep) t1 = MyThread(‘t1‘) t2 = MyThread(‘t2‘) t1.start() t2.start()
结果
task: t1 task: t2 2.0057871341705322 2.0057871341705322
这种方式不常用,知道就行。
继承式多线程
下面是一个继承式多线程的示例,同时启动50个线程,完毕后统一时间
import threading import time def run(n): print(‘task: ‘, n) time.sleep(2) start_time = time.time() t_l = [] #存放线程 for i in range(50): t = threading.Thread(target=run, args=(‘t-%s‘ % i, )) t.start() t_l.append(t) #为了不阻塞其他线程的启动,先放在列表里,最后join for t in t_l: #循环线程列表,执行所有线程 t.join() print(‘All threads have ran down!‘) print(‘Total cost: ‘, time.time() - start_time)
结果
... ... ... task: t-44 task: t-45 task: t-46 task: t-47 task: t-48 task: t-49 All threads have ran down! Total cost: 2.021458387374878
守护线程
在创建新线程时,子线程会从其父线程继承其线程属性,主线程是普通的非守护线程,默认情况下,它所创建的任何线程都是非守护线程。
在默认情况下,新线程通常会生成非守护线程或普通线程,如果新线程在运行,主线程将永远等待,无法正常退出。
主线程执行完毕并且没有任何非守护线程继续运行时,主线程可以正常终止退出了。
注意:
- 必须在启动之前将线程配置为守护程序或非守护程序,否则Python将引发运行时错误;
- 最后守护程序线程不会像普通线程一样正常退出,当程序中的所有非守护程序线程都完成执行时,任何剩余的守护程序线程将在Python退出时被放弃,在设计守护线程时,需要确保在主线程退出时不会产生任何负面影响。
示例
import threading import time start_time = time.time() def run(n): print(‘task: ‘, n) time.sleep(2) print(‘Daemon thread cost: ‘, time.time() - start_time) t_l = [] #存放线程 for i in range(10): t = threading.Thread(target=run, args=(‘t-%s‘ % i, )) t.setDaemon(True) #将当前线程设置为守护线程,daemon希腊神话中的半人半神精灵 t.start() t_l.append(t) #为了不阻塞其他线程的启动,先放在列表里,最后join # for t in t_l: #循环线程列表,执行所有线程 # t.join() print(‘All threads have ran down!‘) print(‘Primary thread cost: ‘, time.time() - start_time)
2个结果,分别是
t.setDaemon(True)
task: t-0 task: t-1 task: t-2 task: t-3 task: t-4 task: t-5 task: t-6 task: t-7 task: t-8 task: All threads have ran down! Primary thread cost: 0.0
t.setDaemon(False)
task: t-0 task: t-1 task: t-2 task: t-3 task: t-4 task: t-5 task: t-6 task: t-7 task: t-8 task: All threads have ran down! t-9 Primary thread cost: 0.0 Daemon thread cost: Daemon thread cost: Daemon thread cost: 2.005704402923584 2.005704402923584 Daemon thread cost: Daemon thread cost: 2.005704402923584 Daemon thread cost: 2.005704402923584 2.005704402923584 Daemon thread cost: 2.005704402923584 2.005704402923584 Daemon thread cost: Daemon thread cost: Daemon thread cost: 2.005704402923584 2.005704402923584 2.005704402923584
可以看到,当子线程设置为守护线程时,主线程并没有理会子线程是否结束(没有执行sleep(2)语句)就已经结束了。当子线程为非守护线程时,主线程等待子线程执行完毕才结束。
以上是关于3.2.1 线程操作的主要内容,如果未能解决你的问题,请参考以下文章
newCacheThreadPool()newFixedThreadPool()newScheduledThreadPool()newSingleThreadExecutor()自定义线程池(代码片段
初识Spring源码 -- doResolveDependency | findAutowireCandidates | @Order@Priority调用排序 | @Autowired注入(代码片段
初识Spring源码 -- doResolveDependency | findAutowireCandidates | @Order@Priority调用排序 | @Autowired注入(代码片段