python 并发之线程
一.什么是线程
- #指的是一条流水线的工作过程,关键的一句话:一个进程内最少自带一个线程,其实进程根本不能执行,进程不是执行单位,是资源的单位,分配资源的单位
- #线程才是执行单位
- #进程:做手机屏幕的工作过程,刚才讲的
- #我们的py文件在执行的时候,如果你站在资源单位的角度来看,我们称为一个主进程,如果站在代码执行的角度来看,它叫做主线程,只是一种形象的说法,其实整个代码的执行过程成为线程,也就是干这个活儿的本身称为线程,但是我们后面学习的时候,我们就称为线程去执行某个任务,其实那某个任务的执行过程称为一个线程,一条流水线的执行过程为线程
- #进程vs线程
- #1 同一个进程内的多个线程是共享该进程的资源的,不同进程内的线程资源肯定是隔离的
- #2 创建线程的开销比创建进程的开销要小的多
- #并发三个任务:1启动三个进程:因为每个进程中有一个线程,但是我一个进程中开启三个线程就够了
- #同一个程序中的三个任务需要执行,你是用三个进程好 ,还是三个线程好?
- #例子:
- # pycharm 三个任务:键盘输入 屏幕输出 自动保存到硬盘
- #如果三个任务是同步的话,你键盘输入的时候,屏幕看不到
- #咱们的pycharm是不是一边输入你边看啊,就是将串行变为了三个并发的任务
- #解决方案:三个进程或者三个线程,哪个方案可行。如果是三个进程,进程的资源是不是隔离的并且开销大,最致命的就是资源隔离,但是用户输入的数据还要给另外一个进程发送过去,进程之间能直接给数据吗?你是不是copy一份给他或者通信啊,但是数据是同一份,我们有必要搞多个进程吗,线程是不是共享资源的,我们是不是可以使用多线程来搞,你线程1输入的数据,线程2能不能看到,你以后的场景还是应用多线程多,而且起线程我们说是不是很快啊,占用资源也小,还能共享同一个进程的资源,不需要将数据来回的copy!
什么是线程
进程有很多优点,它提供了多道编程,让我们感觉我们每个人都拥有自己的CPU和其他资源,可以提高计算机的利用率。很多人就不理解了,既然进程这么优秀,为什么还要线程呢?其实,仔细观察就会发现进程还是有很多缺陷的,主要体现在两点上:
进程只能在一个时间干一件事,如果想同时干两件事或多件事,进程就无能为力了。
进程在执行的过程中如果阻塞,例如等待输入,整个进程就会挂起,即使进程中有些工作不依赖于输入的数据,也将无法执行。
如果这两个缺点理解比较困难的话,举个现实的例子也许你就清楚了:如果把我们上课的过程看成一个进程的话,那么我们要做的是耳朵听老师讲课,手上还要记笔记,脑子还要思考问题,这样才能高效的完成听课的任务。而如果只提供进程这个机制的话,上面这三件事将不能同时执行,同一时间只能做一件事,听的时候就不能记笔记,也不能用脑子思考,这是其一;如果老师在黑板上写演算过程,我们开始记笔记,而老师突然有一步推不下去了,阻塞住了,他在那边思考着,而我们呢,也不能干其他事,即使你想趁此时思考一下刚才没听懂的一个问题都不行,这是其二。
现在你应该明白了进程的缺陷了,而解决的办法很简单,我们完全可以让听、写、思三个独立的过程,并行起来,这样很明显可以提高听课的效率。而实际的操作系统中,也同样引入了这种类似的机制——线程。
二.线程的出现
60年代,在OS中能拥有资源和独立运行的基本单位是进程,然而随着计算机技术的发展,进程出现了很多弊端,一是由于进程是资源拥有者,创建、撤消与切换存在较大的时空开销,因此需要引入轻型进程;二是由于对称多处理机(SMP)出现,可以满足多个运行单位,而多个进程并行开销过大。
在传统操作系统中,每个进程有一个地址空间,而且默认就有一个控制线程
线程顾名思义,就是一条流水线工作的过程,一条流水线必须属于一个车间,一个车间的工作过程是一个进程
车间负责把资源整合到一起,是一个资源单位,而一个车间内至少有一个流水线
流水线的工作需要电源,电源就相当于cpu
所以,进程只是用来把资源集中到一起(进程只是一个资源单位,或者说资源集合),而线程才是cpu上的执行单位。
多线程(即多个控制线程)的概念是,在一个进程中存在多个控制线程,多个控制线程共享该进程的地址空间,相当于一个车间内有多条流水线,都共用一个车间的资源。
例如,北京地铁与上海地铁是不同的进程,而北京地铁里的13号线是一个线程,北京地铁所有的线路共享北京地铁所有的资源,比如所有的乘客可以被所有线路拉。
三.线程与进程的关系
线程与进程的区别可以归纳为以下4点:
- TCB包括以下信息:
- (1)线程状态。
- (2)当线程不运行时,被保存的现场资源。
- (3)一组执行堆栈。
- (4)存放每个线程的局部变量主存区。
- (5)访问同一个进程中的主存和其它资源。
- 用于指示被执行指令序列的程序计数器、保留局部变量、少数状态参数和返回地址等的一组寄存器和堆栈。
2)独立调度和分派的基本单位。
- from threading import Thread
- # def f1(n):
- # print('xx%s'%n)
- #
- #
- # def f2(n):
- # print('ss%s'%n)
- #
- #
- # if __name__ == '__main__':
- # t = Thread(target=f1,args=(1,))
- # t1 = Thread(target=f2,args=(2,))
- # t.start()
- # t1.start()
- # 第二种创建方式
- class Mythread(Thread):
- def run(self):
- print('哈哈哈')
- if __name__ == '__main__':
- t = Mythread()
- t.start()
六.多进程和多线程的效率对比
- import time
- from threading import Thread
- from multiprocessing import Process
- def f1():
- # time.sleep(1) # io密集型 有阻塞
- # 计算型: 无阻塞
- n = 10
- for i in range(10000000):
- n = n + i
- if __name__ == '__main__':
- # 查看一下20个线程执行20个任务的执行时间
- t_s_time = time.time()
- t_list = []
- for i in range(20):
- t =Thread(target=f1,)
- t.start()
- t_list.append(t)
- [tt.join() for tt in t_list]
- t_e_time = time.time()
- t_dif_time = t_e_time - t_s_time
- # 查看一下20个进程执行同样的任务的执行时间
- p_s_time = time.time()
- p_list = []
- for i in range(20):
- p = Process(target=f1,)
- p.start()
- p_list.append(p)
- [pp.join() for pp in p_list]
- p_e_time = time.time()
- p_dif_time = p_e_time - p_s_time
- print('多线程时间:',t_dif_time)
- print('多进程时间:',p_dif_time)
- # 计算型 多线程比多进程费时间
- # io密集型 多线程比多进程省时间
七.线程锁
1.锁
- import time
- from threading import Lock,Thread
- num = 100
- def f1(loc):
- loc.acquire()
- global num
- tmp = num
- tmp -= 1
- time.sleep(0.00001)
- num = tmp
- loc.release()
- if __name__ == '__main__':
- t_loc = Lock()
- t_list = []
- for i in range(10):
- t = Thread(target=f1,args=(t_loc,))
- t.start()
- t_list.append(t)
- [tt.join() for tt in t_list]
- print('主线成的num:',num)
2.死锁
进程也有死锁与递归锁,在进程那里忘记说了,放到这里一切说了额,进程的死锁和线程的是一样的,而且一般情况下进程之间是数据不共享的,不需要加锁,由于线程是对全局的数据共享的,所以对于全局的数据进行操作的时候,要加锁。
所谓死锁: 是指两个或两个以上的进程或线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程,如下就是死锁
- import time
- from threading import Thread,Lock
- def f1(locA,locB):
- locA.acquire()
- print('f1>>>1号抢到了A锁')
- time.sleep(1)
- locB.acquire()
- print('f1>>>1号抢到了B锁')
- locB.release()
- locA.release()
- def f2(locA,locB):
- locB.acquire()
- print('f2>>>2号抢到了A锁')
- time.sleep(1)
- locA.acquire()
- print('f2>>>2号抢到了B锁')
- locA.release()
- locB.release()
- if __name__ == '__main__':
- locA = locB = Lock()
- t1 = Thread(target=f1,args=(locA,locB))
- t2 = Thread(target=f2,args=(locA,locB))
- t1.start()
- t2.start()
解决方案使用递归锁
- import time
- from threading import Thread,RLock
- def f1(locA,locB):
- locA.acquire()
- print('f1>>>1号抢到了A锁')
- time.sleep(1)
- locB.acquire()
- print('f1>>>1号抢到了B锁')
- locB.release()
- locA.release()
- def f2(locA,locB):
- locB.acquire()
- print('f2>>>2号抢到了A锁')
- time.sleep(1)
- locA.acquire()
- # time.sleep(1)
- print('f2>>>2号抢到了B锁')
- locA.release()
- locB.release()
- if __name__ == '__main__':
- locA = locB = RLock()
- #locA = locB = RLock() # 递归锁,维护一个计数器,acquire一次就加1,release就减1
- t1 = Thread(target=f1,args=(locA,locB))
- t2 = Thread(target=f2,args=(locA,locB))
- t1.start()
- t2.start()
3.GIL锁
八.守护线程
- import time
- from threading import Thread
- def f1():
- time.sleep(2)
- print('1号线程')
- def f2():
- time.sleep(3)
- print('2号线程')
- if __name__ == '__main__':
- t1 = Thread(target=f1,)
- t2 = Thread(target=f2,)
- t1.daemon = True
- # t2.daemon = True
- t1.start()
- t2.start()
- print('主线程结束')
守护线程or守护进程区别
- import time
- from threading import Thread
- from multiprocessing import Process
- # 守护进程: 主进程代码执行运行结束,守护进程随之结束
- # 守护线程:守护线程会等待所有非守护线程运行结束才结束
- def f1(s):
- time.sleep(2)
- print('1号%s'%s)
- def f2(s):
- time.sleep(3)
- print('2号%s'%s)
- if __name__ == '__main__':
- # 多线程
- # t1 = Thread(target=f1,args=('线程',))
- # t2 = Thread(target=f2,args=('线程',))
- # t1.daemon = True # 守护线程
- # # t2.daemon = True # 守护线程
- # t1.start()
- # t2.start()
- # print('主线程结束')
- # 多进程
- t1 = Process(target=f1,args=('进程',))
- t2 = Process(target=f2,args=('进程',))
- # t1.daemon = True
- t2.daemon = True
- t1.start()
- t2.start()
- print('主进程结束')
守护线程:等待所有非守护线程的结束才结束
守护进程:主进程代码运行结束,守护进程就随之结束
python 并发之线程的更多相关文章
- Python进程、线程、协程
进程和线程的解释 进程(process)和线程(thread)是操作系统的基本概念,计算机的核心是CPU,它承担了所有的计算任务: 单个CPU一次只能运行一个任务,代表单个CPU总是运行一个进程,其他 ...
- java核心知识点学习----多线程并发之线程同步
1.什么是线程同步? 多线程编程是很有趣的事情,它很容易出现"错误情况",这种情况不是由编码造成的,它是由系统的线程调度造成的,当使用多个线程来访问同一个数据时,很容易出现&quo ...
- python进程、线程、协程(转载)
python 线程与进程简介 进程与线程的历史 我们都知道计算机是由硬件和软件组成的.硬件中的CPU是计算机的核心,它承担计算机的所有任务. 操作系统是运行在硬件之上的软件,是计算机的管理者,它负责资 ...
- Python进程、线程、协程详解
进程与线程的历史 我们都知道计算机是由硬件和软件组成的.硬件中的CPU是计算机的核心,它承担计算机的所有任务. 操作系统是运行在硬件之上的软件,是计算机的管理者,它负责资源的管理和分配.任务的调度. ...
- 理解 Python 中的线程
原地址:http://blog.jobbole.com/52060/ 本文由 伯乐在线 - acmerfight 翻译自 Akshar Raaj.欢迎加入技术翻译小组.转载请参见文章末尾处的要求. 我 ...
- python进阶-------进程线程(二)
Python中的进程线程(二) 一.python中的"锁" 1.GIL锁(全局解释锁) 含义: Python中的线程是操作系统的原生线程,Python虚拟机使用一个全局解释器锁(G ...
- python中的线程技术
#!/user/bin/env python # @Time :2018/7/7 11:42 # @Author :PGIDYSQ #@File :DaemonTest.py import threa ...
- python并发_线程
关于进程的复习: # 管道 # 数据的共享 Manager dict list # 进程池 # cpu个数+1 # ret = map(func,iterable) # 异步 自带close和join ...
- python开发之路:python数据类型(老王版)
python开发之路:python数据类型 你辞职当了某类似微博的社交网站的底层python开发主管,官还算高. 一次老板让你编写一个登陆的程序.咔嚓,编出来了.执行一看,我的妈,报错? 这次你又让媳 ...
随机推荐
- Action详解
简介 Action 是用于处理请求操作的,它是由 StrutsPrepareAndExecuteFilter 分发过来的. 在 Struts2 框架中,Action 是框架的核心类,被称为业务逻辑控制 ...
- spring boot 源码解析11-ConfigurationClassPostProcessor类加载解析
前言 ConfigurationClassPostProcessor实现了BeanDefinitionRegistryPostProcessor接口,该类会在AbstractApplicationCo ...
- Matlab---length函数
1.length函数:计算向量或矩阵的长度 2.用法说明 y = length(x) 函数计算指定向量或矩阵的长度y.如果参数变量x是向量,则返回其长度:如果参数变量是非空矩阵,则length(x)与 ...
- 使用Maven编译运行Storm入门代码(Storm starter)(转)
Storm 官方提供了入门代码(Storm starter),即 Storm安装教程 中所运行的实例(storm-starter-topologies-0.9.6.jar),该入门代码位于 /usr/ ...
- golang包引用
一.我的GOPATH环境变量值如下图: 二.在GOPATH路径下面的的src目录下面的目录名称就是引用里面包的起始位置,如下图: 三.举例说明:这里引用同一个项目的包,源文件“learn/main/m ...
- Django项目:CRM(客户关系管理系统)--43--35PerfectCRM实现CRM重写Admin密码修改
#admin.py # ————————01PerfectCRM基本配置ADMIN———————— from django.contrib import admin # Register your m ...
- JQuery或JS判断浏览器内核版本号以及是否支持W3C盒子模型
jQuery 从 1.9 版开始,移除了 $.browser 和 $.browser.version , 取而代之的是 $.support .在更新的 2.0 版本中,将不再支持 IE 6/7/8. ...
- Javaweb Form表单查询
1.表单(form),是一种可以由用户输入,并提交给服务器端的一个图形界面,有如下性质: (1)表单中可以输入一些内容,这些输入功能由控件提供,叫做表单元素 (2)表单中一般都有一个按钮负责提交 (3 ...
- ZooKeeper的分布式锁实现
分布式锁一般有三种实现方式: 1. 数据库乐观锁: 2. 基于Redis的分布式锁: 3. 基于ZooKeeper的分布式锁. 本篇博客将介绍第三种方式,基于Zookeeper实现分布式锁.虽然网上已 ...
- 2019.9.24 csp-s模拟测试51(a) 反思总结
T1:还在头铁,顺便复习了一下lct[虽然这题用不上因为复杂度不对] 头铁结束. 虽然题目存在换根的操作,实际上并不用真的换根. 2操作中求lca的时候只要考虑原树上root和x.y的lca以及x,y ...