1. 线程定义

  1. 线程是操作系统调度的最小单位
  2. 它被包含在进程之中,是进程中的实际运作单位
  3. 进程本身是无法自己执行的,要操作cpu,必须创建一个线程,线程是一系列指令的集合

线程定义拓展

  1. 线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位
  2. 一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务
  3. 无论你启多少个线程,你有多少个cpu, Python在执行的时候会淡定的在同一时刻只允许一个线程运行
  4. 进程本身是无法自己执行的,要操作cpu,必须创建一个线程,线程是一系列指令的集合
  5. 所有在同一个进程里的线程是共享同一块内存空间的,不同进程间内存空间不同
  6. 同一个进程中的各线程可以相互访问资源,线程可以操作同进程中的其他线程,但进程仅能操作子进程
  7. 两个进程想通信,必须要通过一个中间代理
  8. 对主线程的修改可能回影响其他子线程,对主进程修改不会影响其他进程因为进程间内存相互独立,但是同一进程下的线程共享内存
  9. 一个进程下可以运行多个线程,这些线程之间共享主进程内申请的操作系统资源

使用

用户编写包含线程的程序(每个程序本身都是一个进程)

操作系统“程序切换”进入当前进程

当前进程包含了线程,则启动线程

多个线程,则按照顺序执行,除非抢占

特性

线程,必须在一个存在的进程中启动运行

线程使用进程获得的系统资源,不会像进程那样需要申请CPU等资源

线程无法给予公平执行时间,它可以被其他线程抢占,而进程按照操作系统的设定分配执行时间

每个进程中,都可以启动很多个线程

说明

多线程,也被称为”并发“执行。

线程池

系统启动一个新线程的成本是比较高的,因为它涉及与操作系统的交互。在这种情形下,使用线程池可以很好地提升性能,尤其是当程序中需要创建大量生存期很短暂的线程时,更应该考虑使用线程池。

线程池在系统启动时即创建大量空闲的线程,程序只要将一个函数提交给线程池,线程池就会启动一个空闲的线程来执行它。当该函数执行结束后,该线程并不会死亡,而是再次返回到线程池中变成空闲状态,等待执行下一个函数。

此外,使用线程池可以有效地控制系统中并发线程的数量。当系统中包含有大量的并发线程时,会导致系统性能急剧下降,甚至导致 Python 解释器崩溃,而线程池的最大线程数参数可以控制系统中并发线程的数量不超过此数。

import requests
from concurrent.futures import ThreadPoolExecutordef fetch_request(url):result = requests.get(url)print(result.text)url_list = ['https://www.baidu.com','https://www.google.com/',         #google页面会卡住,知道页面超时后这个进程才结束'http://dig.chouti.com/',          #chouti页面内容会直接返回,不会等待Google页面的返回
]pool = ThreadPoolExecutor(10)            # 创建一个线程池,最多开10个线程
for url in url_list:pool.submit(fetch_request,url)       # 去线程池中获取一个线程,线程去执行fetch_request方法pool.shutdown(True)                      # 主线程自己关闭,让子线程自己拿任务执行

多线程通信

共享变量
创建全局变量,多个线程公用一个全局变量,方便简单。但是坏处就是共享变量容易出现数据竞争,不是线程安全的,解决方法就是使用互斥锁。

变量共享引申出线程同步问题
如果多个线程共同对某个数据修改,则可能出现不可预料的结果,为了保证数据的正确性,需要对多个线程进行同步。 使用Thread对象的Lock和Rlock可以实现简单的线程同步,这两个对象都有acquire方法和release方法,对于那些需要每次只允许一个线程操作的数据,可以将其操作放到acquire和release方法之间。

队列
线程间使用队列进行通信,因为队列所有方法都是线程安全的,所以不会出现线程竞争资源的情况

Queue.Queue 是进程内非阻塞队列

线程中的一些操作

1. for循环同时启动多个线程

import threading
import timedef sayhi(num): #定义每个线程要运行的函数print("running on number:%s" %num)time.sleep(3)
for i in range(50):t = threading.Thread(target=sayhi,args=('t-%s'%i,))t.start()

2. t.join(): 实现所有线程都执行结束后再执行主线程

import threading
import time
start_time = time.time()def sayhi(num): #定义每个线程要运行的函数print("running on number:%s" %num)time.sleep(3)
t_objs = []    #将线程实例对象存储在这个列表中
for i in range(50):t = threading.Thread(target=sayhi,args=('t-%s'%i,))t.start()          #启动一个线程,程序不会阻塞t_objs.append(t)
print(threading.active_count())    #打印当前活跃进程数量
for t in t_objs: #利用for循环等待上面50个线程全部结束t.join()     #优先执行
print(threading.current_thread())    #打印执行这个命令进程print("----------------all threads has finished.....")
print(threading.active_count())
print('cost time:',time.time() - start_time)

3. setDaemon(): 守护线程,主线程退出时,需要子线程随主线程退出

import threading
import time
start_time = time.time()def sayhi(num): #定义每个线程要运行的函数print("running on number:%s" %num)time.sleep(3)
for i in range(50):t = threading.Thread(target=sayhi,args=('t-%s'%i,))t.setDaemon(True)  #把当前线程变成守护线程,必须在t.start()前设置t.start()          #启动一个线程,程序不会阻塞
print('cost time:',time.time() - start_time)

4.GIL全局解释器锁:保证同一时间仅有一个线程对资源有操作权限
作用:在一个进程内,同一时刻只能有一个线程执行
说明:python多线程中GIL锁只是在CPU操作时(如:计算)才是串行的,其他都是并行的,所以比串行快很多
1)为了解决不同线程同时访问同一资源时,数据保护问题,而产生了GIL
2)GIL在解释器的层面限制了程序在同一时间只有一个线程被CPU实际执行,而不管你的程序里实际开了多少条线程
3)为了解决这个问题,CPython自己定义了一个全局解释器锁,同一时间仅仅有一个线程可以拿到这个数据
4)python之所以会产生这种不好的状况是因为python启用一个线程是调用操作系统原生线程,就是C接口
5)但是这仅仅是CPython这个版本的问题,在PyPy,中就没有这种缺陷

4.1线程锁
1)当一个线程对某个资源进行CPU计算的操作时加一个线程锁,只有当前线程计算完成主动释放锁,其他线程才能对其操作
2)这样就可以防止还未计算完成,释放GIL锁后其他线程对这个资源操作导致混乱问题

用户锁使用举例
import time
import threading
lock = threading.Lock()          #1 生成全局锁
def addNum():global num                  #2 在每个线程中都获取这个全局变量print('--get num:',num )time.sleep(1)lock.acquire()              #3 修改数据前加锁num  -= 1                   #4 对此公共变量进行-1操作lock.release()              #5 修改后释放

5. Semaphore(信号量)

  1. 互斥锁 同时只允许一个线程更改数据,而Semaphore是同时允许一定数量的线程更改数据
  2. 比如厕所有3个坑,那最多只允许3个人上厕所,后面的人只能等里面有人出来了才能再进去
  3. 作用就是同一时刻允许运行的线程数量

进程和线程的区别

一个进程中的各个线程与主进程共享相同的资源,与进程间互相独立相比,线程之间信息共享和通信更加容易(都在进程中,并且共享内存等)。

线程一般以并发执行,正是由于这种并发和数据共享机制,使多任务间的协作成为可能。

进程一般以并行执行,这种并行能使得程序能同时在多个CPU上运行;

区别于多个线程只能在进程申请到的的“时间片”内运行(一个CPU内的进程,启动了多个线程,线程调度共享这个进程的可执行时间片),进程可以真正实现程序的“同时”运行(多个CPU同时运行)。
简单来说就是

  1. 进程包含线程
  2. 线程共享内存空间
  3. 进程内存是独立的(不可互相访问)
  4. 进程可以生成子进程,子进程之间互相不能互相访问(相当于在父级进程克隆两个子进程)
  5. 在一个进程里面线程之间可以交流。两个进程想通信,必须通过一个中间代理来实现
  6. 创建新线程很简单,创建新进程需要对其父进程进行克隆。
  7. 一个线程可以控制或操作同一个进程里面的其它线程。但进程只能操作子进程。
  8. 父进程可以修改不影响子进程,但不能修改。
  9. 线程可以帮助应用程序同时做几件事

进程和线程的常用应用场景

一般来说,在Python中编写并发程序的经验:

计算密集型任务使用多进程

IO密集型(如:网络通讯)任务使用多线程,较少使用多进程.

这是由于 IO操作需要独占资源,比如:

网络通讯(微观上每次只有一个人说话,宏观上看起来像同时聊天)每次只能有一个人说话

文件读写同时只能有一个程序操作(如果两个程序同时给同一个文件写入 ‘a’, ‘b’,那么到底写入文件的哪个呢?)

都需要控制资源每次只能有一个程序在使用,在多线程中,由主进程申请IO资源,多线程逐个执行,哪怕抢占了,也是逐个运行,感觉上“多线程”并发执行了。

如果多进程,除非一个进程结束,否则另外一个完全不能用,显然多进程就“浪费”资源了。

当然如上解释可能还不足够立即理解问题所在,让我们通过不断的实操来体验其中的“门道”。

Python中的 线程相关推荐

  1. python停止线程池_详解python中Threadpool线程池任务终止示例代码

    需求 加入我们需要处理一串个位数(0~9),奇数时需要循环打印它:偶数则等待对应时长并完成所有任务:0则是错误,但不需要终止任务,可以自定义一些处理. 关键点 定义func函数处理需求 callbac ...

  2. python脚本自动运行失败_解决Python中定时任务线程无法自动退出的问题

    python的线程有一个类叫Timer可以,用来创建定时任务,但是它的问题是只能运行一次,如果要重复执行,则只能在任务中再调用一次timer,但这样就存在新的问题了,就是在主进程退出后,不能正常退出子 ...

  3. Python中的线程间通信

    Python中的线程间通信 文章目录 Python中的线程间通信 1.Queue 2.同步机制 1.Event 2.Semaphore(信号量) 3.Lock(锁) 4.RLock(可重入锁) 5.C ...

  4. python线程安全的计数器_+ =运算符在Python中是线程安全的吗?

    + =运算符在Python中是线程安全的吗? 我想为实验创建一个非线程安全的代码块,这些是2个线程将要调用的函数. c = 0 def increment(): c += 1 def decremen ...

  5. python threading timer 退出_解决Python中定时任务线程无法自动退出的问题

    python的线程有一个类叫Timer可以,用来创建定时任务,但是它的问题是只能运行一次,如果要重复执行,则只能在任务中再调用一次timer,但这样就存在新的问题了,就是在主进程退出后,不能正常退出子 ...

  6. python中的线程技术

    #!/user/bin/env python # @Time :2018/7/7 11:42 # @Author :PGIDYSQ #@File :DaemonTest.py import threa ...

  7. python协程和线程区别_python中的线程和协程之间有什么区别

    一.首先我们来了解一下线程和协程的概念1.线程线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源( ...

  8. 解析Python中的线程与进程

    1 基础知识 现在的 PC 都是多核的,使用多线程能充分利用 CPU 来提供程序的执行效率. 1.1 线程 线程是一个基本的 CPU 执行单元.它必须依托于进程存活.一个线程是一个execution ...

  9. python多线程实现同步的方式_深入解析Python中的线程同步方法

    同步访问共享资源 在使用线程的时候,一个很重要的问题是要避免多个线程对同一变量或其它资源的访问冲突.一旦你稍不留神,重叠访问.在多个线程中修改(共享资源)等这些操作会导致各种各样的问题:更严重的是,这 ...

  10. python中的线程和进程。

    1.什么是进程和线程. 1.1 进程的概念 进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础,每个进程都有自己的地址空间. ...

最新文章

  1. 今天且明白父母为什么生死度外的让孩子们读书
  2. UVa11770 - Lighting Away(排序+DFS)
  3. 微信小程序自定义状态栏
  4. mysql小鲸鱼_杀死一只小鲸鱼
  5. C#.net工作笔记001---Linq对象查询,排序,分组,去重在工作中的使用_随时更新
  6. Linux Shell笔记4 正则表达式
  7. Android 四大组件学习之Service二
  8. 全网首发:sqlite-jdbc在UOS上弹窗提示的解决办法
  9. Dbgview,本机内核打印的注册表配置
  10. gms认证流程_Android P(9.0)GMS认证新要求
  11. web运维:跨域(NGINX跨域配置为例)
  12. du命令排序文件大小
  13. python redis decode_responses
  14. QT将10进制转换为2进制与16进制
  15. 6阶子群同构于s3或者z6_[2017年整理]离散数学复习.ppt
  16. ARM服务器安装CentOS7.4
  17. 第一次阅读与准备作业
  18. Inspection info: Reports octal integer literals. Some coding standards prohibit the use of octal...
  19. CSharp与Python中的输入输出语句对比
  20. SpringCloud微服务技术实践与总结(基础篇)

热门文章

  1. win7更新_微软停止更新 Win7,你也许关心这四个问题。
  2. 纸牌游戏设计制作《摸鱼2》(C语言)
  3. 利用Cocos+Matchvs开发的IO类游戏源码分享
  4. maven阿里镜像配置setting文件
  5. 【JavaScript 笔记 ,全套教程百度云
  6. opentsdb java开发,OpenTSDB的读写API
  7. 写给未来自己的信(2011,2019,2029,2039)
  8. DIV CSS3 text-shadow字体阴影
  9. 什么是DNS劫持与DNS劫持常见手段总结
  10. java modbus crc_modbus crc计算工具(Modbus CRC校验工具)