多任务的概念

什么叫“多任务”呢?简单地说,就是操作系统可以同时运行多个任务。打个比方,你一边在用浏览器上网,一边在听MP3,一边在用Word赶作业,这就是多任务,至少同时有3个任务正在运行。还有很多任务悄悄地在后台同时运行着,只是桌面上没有显示而已。

现在,多核CPU已经非常普及了,但是,即使过去的单核CPU,也可以执行多任务。由于CPU执行代码都是顺序执行的,那么,单核CPU是怎么执行多任务的呢?

答案就是操作系统轮流让各个任务交替执行,任务1执行0.01秒,切换到任务2,任务2执行0.01秒,再切换到任务3,执行0.01秒……这样反复执行下去。表面上看,每个任务都是交替执行的,但是,由于CPU的执行速度实在是太快了,我们感觉就像所有任务都在同时执行一样。

真正的并行执行多任务只能在多核CPU上实现,但是,由于任务数量远远多于CPU的核心数量,所以,操作系统也会自动把很多任务轮流调度到每个核心上执行。

注意:

  • 并发:指的是任务数多余cpu核数,通过操作系统的各种任务调度算法,实现用多个任务“一起”执行(实际上总有一些任务不在执行,因为切换任务的速度相当快,看上去一起执行而已)
  • 并行:指的是任务数小于等于cpu核数,即任务真的是一起执行的

线程基础

python的thread模块是比较底层的模块,python的threading模块是对thread做了一些包装的,可以更加方便的被使用

单线程执行

import time

def test():
print("test...")
time.sleep(1) if __name__ == '__main__': for i in range(5):
test()

执行效果:程序在控制台每隔一秒打印test...

多线程执行

import time
import threading def test():
print("test...")
time.sleep(1) if __name__ == '__main__': for i in range(5):
t = threading.Thread(target=test)
t.start() # 启动线程

执行效果:程序在控制台一下子输出五行test...,等待1秒左右结束

说明:

  1. 可以明显看出使用了多线程并发的操作,花费时间要短很多
  2. 当调用start()时,才会真正的创建线程,并且开始执行

主线程会等待所有子线程结束后才结束

import time
import threading def playPhone(): print('玩手机...')
time.sleep(1) def eat(): print("吃东西...")
time.sleep(1) if __name__ == '__main__': print("--开始--") t1 = threading.Thread(target=playPhone)
t1.start() t2 = threading.Thread(target=eat)
t2.start() print('--执行结束')

执行效果:主线程阻塞1秒左右后程序结束,说明主线程在等待其他线程执行完毕。

查看线程数量

          print('玩手机...')
time.sleep(1) def eat(): for i in range(10):
print("吃东西...")
time.sleep(1) if __name__ == '__main__': print("--开始--") t1 = threading.Thread(target=playPhone)
t1.start() t2 = threading.Thread(target=eat)
t2.start() # 查看正在执行的线程数量
while True:
length = len(threading.enumerate())
print("当前运行的线程数量:%d" % length)
print("这些线程是:%s" % str(threading.enumerate())) if length == 1:
break time.sleep(0.5) print('--执行结束')

在python中,调用threading.enumerate()能获取当前正在运行的所有线程,返回值是一个list,调用length()函数并传入该list对象就获取到当前运行线程的数量。

线程-注意点

线程执行代码的封装

通过上一篇,能够看出,通过使用threading模块能完成多任务的程序开发,为了让每个线程的封装性更完美,所以使用threading模块时,往往会定义一个新的子类class,只要继承threading.Thread就可以了,然后重写run方法。

示例如下:

import time
import threading class MyThread(threading.Thread): def run(self):
for i in range(5):
time.sleep(1)
print("我是%s@%d" % (self.name, i)) if __name__ == "__main__":
mt = MyThread()
mt.start()

运行结果如下:

我是Thread-1@0
我是Thread-1@1
我是Thread-1@2
我是Thread-1@3
我是Thread-1@4

python的threading.Thread类有一个run方法,用于定义线程的功能函数,可以在自己的线程类中覆盖该方法。而创建自己的线程实例后,通过Thread类的start方法,可以启动该线程,交给python虚拟机进行调度,当该线程获得执行的机会时,就会调用run方法执行线程。

线程的执行顺序

mport time
import threading class MyThread(threading.Thread): def run(self):
for i in range(5):
time.sleep(1)
print("我是%s@%d" % (self.name, i)) if __name__ == "__main__": for i in range(5):
mt = MyThread()
mt.start()

执行结果(运行的结果可能不一样,但是大体是一致的):

我是Thread-5@0
我是Thread-2@0
我是Thread-3@0
我是Thread-4@0
我是Thread-1@0
我是Thread-3@1
我是Thread-4@1
我是Thread-2@1
我是Thread-5@1
我是Thread-1@1
我是Thread-3@2
我是Thread-4@2
我是Thread-2@2
我是Thread-5@2
我是Thread-1@2
我是Thread-3@3
我是Thread-4@3
我是Thread-2@3
我是Thread-5@3
我是Thread-1@3
我是Thread-3@4
我是Thread-4@4
我是Thread-5@4
我是Thread-2@4
我是Thread-1@4

从代码和执行结果我们可以看出,多线程程序的执行顺序是不确定的。当执行到sleep语句时,线程将被阻塞(Blocked),到sleep结束后,线程进入就绪(Runnable)状态,等待调度。而线程调度将自行选择一个线程执行。上面的代码中只能保证每个线程都运行完整个run函数,但是线程的启动顺序、run函数中每次循环的执行顺序都不能确定。

总结

  1. 每个线程默认有一个名字,尽管上面的例子中没有指定线程对象的name,但是python会自动为线程指定一个名字。
  2. 当线程的run()方法结束时该线程完成。
  3. 无法控制线程调度程序,但可以通过别的方式来影响线程调度的方式。

python多任务-线程的更多相关文章

  1. Python 多任务(线程) day1

    多任务就是可以让一台电脑同时执行多个命令. 以前的单核cpu是怎么做到同时执行多个命令的?(时间片轮转) ——其实以前的单核CPU是让操作系统交替执行命令,每个任务执行0.01秒,这样看起来就像是在同 ...

  2. Python多任务—线程

    并发:指的是任务数多余cpu核数,通过操作系统的各种任务调度算法,实现用多个任务“一起”执行(实际上总有一些任务不在执行,因为切换任务的速度相当快,看上去一起执行而已) 并行:指的是任务数小于等于cp ...

  3. Python 多任务(线程) day2 (1)

    结论:多线程全局变量是共享的 (03) 因为多线程一般是配合使用,如果不共享,那么就要等到一个线程执行完,再把变量传递给另一个线程,就变成单线程了 但是如果多个线程同时需要修改一个全局变量,就会出现资 ...

  4. Python(线程进程3)

    四 协程 协程,又称微线程,纤程.英文名Coroutine.一句话说明什么是线程:协程是一种用户态的轻量级线程. 协程拥有自己的寄存器上下文和栈.协程调度切换时,将寄存器上下文和栈保存到其他地方,在切 ...

  5. Python之线程、进程和协程

    python之线程.进程和协程 目录: 引言 一.线程 1.1 普通的多线程 1.2 自定义线程类 1.3 线程锁 1.3.1 未使用锁 1.3.2 普通锁Lock和RLock 1.3.3 信号量(S ...

  6. python/进程线程的总结

    python/进程线程的总结 一.进程和线程的描述: 进程:最小的资源管理单位 线程:最小的执行单位 执行一个进程时就默认执行一个线程(主线程) 进程和线程的工作方式: 串行: 假如共有A.B.C任务 ...

  7. 在python中单线程,多线程,多进程对CPU的利用率实测以及GIL原理分析

    首先关于在python中单线程,多线程,多进程对cpu的利用率实测如下: 单线程,多线程,多进程测试代码使用死循环. 1)单线程: 2)多线程: 3)多进程: 查看cpu使用效率: 开始观察分别执行时 ...

  8. python中线程和进程(一)

    目录 进程和线程 Python中的线程 1. Thread类 2. 线程的启动 3. 线程的传参 4. 线程的属性和方法 5. daemon线程和non-daemon线程 6. join方法 7. 定 ...

  9. 一文了解Python的线程

    问题 什么是线程? 如何创建.执行线程? 如何使用线程池ThreadPoolExecutor? 如何避免资源竞争问题? 如何使用Python中线程模块threading提供的常用工具? 目录 1. 什 ...

随机推荐

  1. 用apache和tomcat搭建集群,实现负载均衡

    型的企业应用每天都需要承受巨大的访问量,在着巨大访问量的背后有数台服务器支撑着,如果一台服务器崩溃了,那么其他服务器可以使企业应用继续运行,用户对服务器的运作是透明化的,如何实现这种透明化呢?由如下问 ...

  2. sql并集union和union all的区别

    union : 对两个结果集进行并集操作,不包括重复行,同时进行默认规则的排序; union all:  对两个结果集进行并集操作,包括重复行,不进行排序; intersect : 对两个结果集进行交 ...

  3. 六、activiti工作流-流程定义查询

    本节主要讲流程定义查询.查询某个流程设计图片并保存到本地中.查询最新版本的流程定义集合.删除所有key相同的定义 先创建一个java类 package com.java.procdef; import ...

  4. Scala - 快速学习08 - 函数式编程:高阶函数

    函数式编程的崛起 函数式编程中的“值不可变性”避免了对公共的可变状态进行同步访问控制的复杂问题,能够较好满足分布式并行编程的需求,适应大数据时代的到来. 函数是第一等公民 可以作为实参传递给另外一个函 ...

  5. Python中的高级变量类型

    高级变量类型 目标 列表 元组 字典 字符串 公共方法 变量高级 知识点回顾 Python 中数据类型可以分为 数字型 和 非数字型 数字型 整型 (int) 浮点型(float) 布尔型(bool) ...

  6. c++模板参数——数值类型推断

    模板类中,或模板函数中,若限定模板参数为数值类型,可以使用如下方式进行判断. template<typename T> Fmt::Fmt(const char *fmt, T val) { ...

  7. 运维笔记--docker odoo镜像 运行异常处理

    场景描述: 镜像来源,dockerhub odoo官方镜像:https://hub.docker.com/_/odoo odoo镜像运行一段时间后,出现下述异常,可能是触发某个未知bug:该现象在生产 ...

  8. 扒一扒.net、.net framework、mono和Unity

    zhaichao 标签: .net.net frameworkc#monounity 2017-04-23 14:39 425人阅读 评论(0) 收藏 举报 版权声明:本文为博主原创文章,未经博主允许 ...

  9. SHOW INDEX 你用过吗???

    mysql中 show 包含了很多指令,例如show table status, show innodb 等等等, 今天来讲讲mysql中SHOW  INDEX FROM tableName 本例中用 ...

  10. 利用 ELK 搭建 Docker 容器化应用日志中心

    利用 ELK 搭建 Docker 容器化应用日志中心 概述 应用一旦容器化以后,需要考虑的就是如何采集位于 Docker 容器中的应用程序的打印日志供运维分析.典型的比如SpringBoot应用的日志 ...