python语法基础-并发编程-线程-长期维护
############### 守护线程 ##############
from threading import Thread
import time
def func1(name):
while True:
print(11111111)
time.sleep(1) def func2(name):
print(2222222)
time.sleep(5) if __name__ == '__main__':
t=Thread(target=func1,args=('andy',))
t.daemon = True # 主线程代码结束,子线程随之结束,
# 不加守护线程,主线程就会等待子线程的结束,然后主线程才会结束,
t.start() t2=Thread(target=func2,args=('lucy',))
t2.start()
# 主线程会等待子线程结束
print('主线程')
print(t.is_alive())
'''
11111111
2222222
主线程
True
11111111
11111111
11111111
11111111
11111111
'''
分析:
# 所以进程的守护进程,和线程的守护进程是有不一样的点的
# 1.对主进程来说,运行完毕指的是主进程代码运行完毕
# 2.对主线程来说,运行完毕指的是主线程所在的进程内所有非守护线程统统运行完毕,主线程才算运行完毕 #1 主进程在其代码结束后就已经算运行完毕了(守护进程在此时就被回收),
# 然后主进程会一直等非守护的子进程都运行完毕后回收子进程的资源(否则会产生僵尸进程),才会结束,
#2 主线程在其他非守护线程运行完毕后才算运行完毕(守护线程在此时就被回收)。
# 因为主线程的结束意味着进程的结束,进程整体的资源都将被回收,而进程必须保证非守护线程都运行完毕后才能结束。
############### 同步锁 ##############
# 线程加同步锁,就是说其他的线程要等待那个拿到锁的线程结束了之后才可以去操作数据,也可以叫做互斥锁, # 模拟多线程出错的场景,
# 全局的n是10,然后创建10个线程,去执行n-1的操作,
# 结果按理说应该是0,但是结果是9,
# 为什么?
# 10个线程去拿n=10,所有人拿的都是10,然后都同步减去1,然后返回都是9,所以是9,
# 但是有GIL锁啊,为什么还会产生这种情况?
# 还是因为时间片轮转,你取到了数据,但是还没有来得及减1,这个值就被其他的线程拿走了,还是10, from threading import Lock, Thread
import time
# def func():
# global n
# temp = n
# time.sleep(0.2)
# n= temp-1
#
# n = 10
# t_list=[]
# for i in range(10):
# t= Thread(target=func)
# t.start()
# t_list.append(t)
#
#
# for i in t_list:t.join()
# print(n) # 模拟线程加锁的情况,然后看看结果
# 这样加了锁之后,结果应该就是0了,是的,结果是0了
# 加锁降低了性能,但是保证了数据的安全性, # def func(lock):
# global n
# lock.acquire()
# temp = n
# time.sleep(0.2)
# n= temp-1
# lock.release()
#
# n = 10
# t_list=[]
# lock = Lock()
#
# for i in range(10):
# t= Thread(target=func,args=(lock,))
# t.start()
# t_list.append(t)
#
#
# for i in t_list:t.join()
# print(n)
互斥锁和join的区别
#有的同学可能有疑问:既然加锁会让运行变成串行,那么我在start之后立即使用join,就不用加锁了啊,也是串行的效果啊
#没错:在start之后立刻使用jion,肯定会将100个任务的执行变成串行,毫无疑问,最终n的结果也肯定是0,是安全的,但问题是
#start后立即join:任务内的所有代码都是串行执行的,而加锁,只是加锁的部分即修改共享数据的部分是串行的
#单从保证数据安全方面,二者都可以实现,但很明显是加锁的效率更高.
############### 死锁和递归锁 ##############
# 现在看看科学家吃面的问题,看看死锁的场景
# 这个例子是只有拿到面和叉子,才可以吃面,
from threading import Lock, Thread
import time
# noodle_lock = Lock()
# fork_lock = Lock()
# def eat1(name):
# noodle_lock.acquire()
# print("%s拿到面条"%name)
# fork_lock.acquire()
# print("%s拿到叉子"%name)
# print("吃面")
# fork_lock.release()
# noodle_lock.release()
#
#
#
# def eat2(name):
# fork_lock.acquire()
# print("%s拿到叉子"%name)
# time.sleep(1)
# noodle_lock.acquire()
# print("%s拿到面条"%name)
# print("吃面")
# noodle_lock.release()
# fork_lock.release()
#
# Thread(target=eat1,args=("name1",)).start()
# Thread(target=eat2,args=("name2",)).start()
# Thread(target=eat1,args=("name3",)).start()
# Thread(target=eat1,args=("name4",)).start()
#
# """
# name1拿到面条
# name1拿到叉子
# 吃面
# name2拿到叉子
# name3拿到面条
# 这种情况不同的人拿到了叉子和面条,就无法进行了,就阻塞了,就死锁了,
# 怎么解决?有一个递归锁
# """ # 递归锁,来解决死锁的问题
# # 你可以看做是钥匙串上面的两把钥匙,一旦你拿到了一把钥匙,就证明你拿到了整个钥匙串了,
from threading import RLock noodle_lock = fork_lock = RLock() # 你可以看做是钥匙串上面的两把钥匙 def eat1(name):
noodle_lock.acquire()
print("%s拿到面条" % name)
fork_lock.acquire()
print("%s拿到叉子" % name)
print("吃面")
fork_lock.release()
noodle_lock.release() def eat2(name):
fork_lock.acquire()
print("%s拿到叉子" % name)
time.sleep(1)
noodle_lock.acquire()
print("%s拿到面条" % name)
print("吃面")
noodle_lock.release()
fork_lock.release() Thread(target=eat1, args=("name1",)).start()
Thread(target=eat2, args=("name2",)).start()
Thread(target=eat1, args=("name3",)).start()
Thread(target=eat2, args=("name4",)).start()
############### 全局解释器锁GIL ##############
"""
全局解释器锁GIL 首先需要明确的一点是GIL并不是Python的特性,它是在实现Python解析器(CPython)时所引入的一个概念。 Python也一样,同样一段代码可以通过CPython,PyPy,Psyco等不同的Python执行环境来执行。
像其中的JPython就没有GIL。然而因为CPython是大部分环境下默认的Python执行环境。
所以在很多人的概念里CPython就是Python,也就想当然的把GIL归结为Python语言的缺陷。
所以这里要先明确一点:GIL并不是Python的特性,Python完全可以不依赖于GIL。 简单来说,在Cpython解释器中,因为有GIL锁的存在同一个进程下开启的多线程,同一时刻只能有一个线程执行,无法利用多核优势。 同一个数据,多个线程去操作,也会出现问题,所以也有线程锁的概念,
这种机制叫做全局解释器锁,英文GIL,
这种机制的结果就是:同一时间只有一个线程去访问cpu,
你想要访问数据,就必须拿到这个钥匙,
这个锁,锁的是线程,不是锁的某一个数据,
这样不好,因为同一时间cpu上面只有一个线程,这样不能充分的利用cpu
这不是Python语言的问题,这是cPython解释器的问题,如果你有一个jPython解释器就行 这的确是一个弊病,导致Python的多线程形同虚设,
那么为什么不解决呢?
java和c++都是编译性语言,Python是一个解释性语言,php也是,
目前解释性语言就是存在这个问题,这个矛盾还不可调和, 是否把数据加锁就可以了,也是不行的,数据太多了,这么大范围的加锁,最终导致的效率,还不如全局解释器锁的性能好, 常见问题1
我们有了GIL锁为什么还要自己在代码中加锁呢?
还是因为时间片轮转,你取到了数据,但是还没有来得及减1,这个值就被其他的线程拿走了,还是10,
常见问题2
有了GIL的存在,同一时刻同一进程中只有一个线程被执行,进程可以利用多核,但是开销大,
而Python的多线程开销小,但却无法利用多核优势,也就是说Python这语言难堪大用。
解答:
其实编程所解决的现实问题大致分为IO密集型和计算密集型。
对于IO密集型的场景,Python的多线程编程完全OK,而对于计算密集型的场景,
Python中有很多成熟的模块或框架如Pandas等能够提高计算效率。 在cPython解释器下的Python程序,在同一时间,多个线程只能有一个线程在cpu执行,这不意味着多线程就没有意义了,
解答:
因为只有涉及到计算的地方才会使用到CPU,
高CPU:所以在计算类的高cpu利用率的,Python不占优势,
高IO:我们写的代码很多都涉及到这种,
比如qq聊天,处理日志文件,爬取网页,处理web请求,读写数据库,都是高io的,都是有Python用武之地的,
所以Python不能处理计算类高的问题,这不影响他在web编程的作用,
如果你真的需要高并发呢,你可以使用多进程,就不会有GIL锁了, """
谈下python的GIL
GIL 是python的全局解释器锁,同一进程中假如有多个线程运行,一个线程在运行python程序的时候会霸占python解释器(加了一把锁即GIL),
使该进程内的其他线程无法运行,等该线程运行完后其他线程才能运行。如果线程运行过程中遇到耗时操作,则解释器锁解开,
使其他线程运行。所以在多线程中,线程的运行仍是有先后顺序的,并不是同时进行。 多进程中因为每个进程都能被系统分配资源,相当于每个进程有了一个python解释器,所以多进程可以实现多个进程的同时运行,缺点是进程系统资源开销大
############### 线程,队列 ##############
# 线程,队列 # 加锁会自己写代码,不方便,我们可以使用队列
# 队列内置了很多的锁,可以保证数据安全,
# queue队列 :使用import queue,用法与进程Queue一样 import queue q = queue.Queue() q.put()
q.put_nowait() # 这个会报错
q.get()
q.get_nowait() # 这个会报错, # 队列的特点:先进先出, queue.LifoQueue() # 栈,先进后出,
q.put(1)
q.put(2)
q.put(3)
print(q.get())
print(q.get())
print(q.get()) queue.PriorityQueue() # 优先级队列,
# put进入一个元组
# 元组的第一个元素是优先级,(通常也可以是数字,或者也可以是非数字之间的比较) 数字越小,优先级越高
q.put(20, 1)
q.put(10, 2) # 数字越小,优先级越高,优先级一样,就是按照和ASk码排,
q.put(30, 3)
print(q.get())
print(q.get())
print(q.get()) # 总结:
# 1,普通队列
# 2,栈
# 3,优先级队列,
# 这三种都不会出现多线程抢占资源,
###########################################
############################################
python语法基础-并发编程-线程-长期维护的更多相关文章
- python语法基础-并发编程-线程-线程理论和线程的启动
####################### 线程介绍 ############################## """ 线程介绍 为什 ...
- python语法基础-并发编程-进程-进程理论和进程的开启
############################################## """ 并发编程的相关概念: 进程 1,运行中的程序,就是进程,程序是没有生 ...
- python语法基础-并发编程-进程-进程锁和进程间通信
############### 守护进程 ############## """ 守护进程 父进程中将一个子进程设置为守护进程,那么这个子进程会随着主进程的结束而结束 ...
- python语法基础-并发编程-协程-长期维护
############### 协程 ############## # 协程 # 小知识点, # 协程和进程和线程一样都是实现并发的手段, # 开启一个线程,创建一个线程,还是需要开销, ...
- python语法基础-并发编程-进程-进程池以及回调函数
############### 进程池 ############## """ 进程池的概念 为什么会有进程池? 1,因为每次开启一个进程,都需要创建一个内存空间 ...
- python语法基础-函数-装饰器-长期维护
######################################################### # 装饰器 # 装饰器非常重要,面试Python的公司必问, # 原则:开放封闭原则 ...
- python语法基础-并发编程-进程-其他
############### 多进程的信号量 ############## # 多进程的信号量 from multiprocessing import Process import ti ...
- python语法基础-网络编程-TCP协议和UDP协议
############### 网络编程 ############## """ 网络编程 学习了Python基础之后,包括函数,面向对象等,你就可以开发了,你 ...
- python语法基础-网络编程-HTTP协议
############### HTTP协议 ############## """ 当你在浏览器地址栏敲入“http://www.cnblogs.com/”, ...
随机推荐
- h5-动画基本介绍
1.介绍 *{ ; ; } div{ width: 200px; height: 200px; background-color: #5aff61; /*添加动画效果*/ /*1.animation- ...
- XML文件读写编码不是UTF-8的问题
FileWriter和FileReader在写.读文件时,使用系统当前默认的编码方式. 在中文win下encoding基本是GB2312,在英文win下基本是ISO-8859-1.所以要创建一个UTF ...
- Thread.sleep 与Thread.currentThread.sleep 相同
package com.citi.tm.api.trade.mongo; public class ThreadTest { public static void main(String[] args ...
- C语言-数组的深入学习
深入学习一下数组1.从内存角度来讲:数组变量就是一次分配多个变量,而且这些变量的地址是连续的,也就是存放这些变量的存储单元是依次相连接的.而且这多个变量必须单独访问,不可以一起访问的.因为他们的地址彼 ...
- Codeforces Round #568 (Div. 2)网卡&垫底记
这场和div3差不多嘛(后来发现就是div3),就是网太卡10min交一发就不错了,简直自闭. A 签到. B 记录每一段的字母数,满足条件即:段数相同+字母相同+字母数下>=上. #inclu ...
- 2. Rabbitmq php 安装 amqp 拓展
记录一下 使用 rabbitmq 安装 amqp 拓展 环境 ubuntu 安装目录在 /user/local 下进行 1. 安装 wget apt-get update apt-get inst ...
- POJ 3660 Cow Contest【Floyd 传递闭包】
传送门:http://poj.org/problem?id=3660 题意:有n头牛, 给你m对关系.(a, b)表示牛a能打败牛b, 求在给出的这些关系下, 能确定多少头牛的排名. 传递闭包: 关系 ...
- js实现placehoider效果
placeholder作为input输入框提示语很好用,但是低版本ie却不支持,对于只有提示语的输入框并不适用 <input type="text" value=" ...
- 京东云数据库 RDS助力企业便捷运维
iPhone6发布那年,京东在国贸等商圈送货最快速度数分钟,包括从下单到送达.这是一个极端的富含营销因素例子.即便如此,常态来看,隔天到货的这种业务模式,也是基于同样的支撑:营销业务.物流业务,大数据 ...
- Linux 系统查看服务器SN序列号以及服务器型号
1.单独查看服务器的序列号 [root@localhost ~]# dmidecode -t system | grep 'Serial Number' Serial Number: 2102310Y ...