###############    守护线程    ##############

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语法基础-并发编程-线程-长期维护的更多相关文章

  1. python语法基础-并发编程-线程-线程理论和线程的启动

    #######################       线程介绍         ############################## """ 线程介绍 为什 ...

  2. python语法基础-并发编程-进程-进程理论和进程的开启

    ############################################## """ 并发编程的相关概念: 进程 1,运行中的程序,就是进程,程序是没有生 ...

  3. python语法基础-并发编程-进程-进程锁和进程间通信

    ###############   守护进程  ############## """ 守护进程 父进程中将一个子进程设置为守护进程,那么这个子进程会随着主进程的结束而结束 ...

  4. python语法基础-并发编程-协程-长期维护

    ###############    协程    ############## # 协程 # 小知识点, # 协程和进程和线程一样都是实现并发的手段, # 开启一个线程,创建一个线程,还是需要开销, ...

  5. python语法基础-并发编程-进程-进程池以及回调函数

    ###############   进程池    ############## """ 进程池的概念 为什么会有进程池? 1,因为每次开启一个进程,都需要创建一个内存空间 ...

  6. python语法基础-函数-装饰器-长期维护

    ######################################################### # 装饰器 # 装饰器非常重要,面试Python的公司必问, # 原则:开放封闭原则 ...

  7. python语法基础-并发编程-进程-其他

    ###############    多进程的信号量    ############## # 多进程的信号量 from multiprocessing import Process import ti ...

  8. python语法基础-网络编程-TCP协议和UDP协议

    ###############    网络编程    ############## """ 网络编程 学习了Python基础之后,包括函数,面向对象等,你就可以开发了,你 ...

  9. python语法基础-网络编程-HTTP协议

    ###############    HTTP协议    ############## """ 当你在浏览器地址栏敲入“http://www.cnblogs.com/”, ...

随机推荐

  1. soupui--替换整个case的url

    添加新的URL 随便进入一个case的[REST]step,添加新的url 更换URL 添加完之后双击想要更换url的case,在弹出的窗口中点击URL按钮 在弹出的set endpoint窗口中选择 ...

  2. (day 1)创建项目--3【创建应用】

    创建步骤 1.打开命令行,进入项目中manage.py的同级目录 2.在命令行输入 python manage.py startapp blog 3.添加应用名到settings.py的INSTALL ...

  3. 吴裕雄--天生自然MySQL学习笔记:MySQL 删除数据表

    MySQL中删除数据表是非常容易操作的, 但是在进行删除表操作时要非常小心,因为执行删除命令后所有数据都会消失. 语法 以下为删除MySQL数据表的通用语法: DROP TABLE table_nam ...

  4. h5-立方体

    1.制作一个立方体:首先要有6个面 <div class="box"> <div class="front">front</div ...

  5. Python说文解字_杂谈03

    1. 我们从前面的知识得到,所有的类都要继承自object这个基类(超类),另外我们知道“继承”可以继承类的属性和方法.我们起始通过type创建类的时候,自然而然的也会从ojbect继承他的一些属性和 ...

  6. 微信支付的Demo

    是在一个子项目完成的, 依赖: <dependencies> <!-- spring-boot--> <dependency> <groupId>org ...

  7. strpos用法

    语法 strpos(string,find,start) 参数 描述 string 必需.规定要搜索的字符串. find 必需.规定要查找的字符串. start 可选.规定在何处开始搜索.   技术细 ...

  8. git常用操作及其基本命令

    克隆远程仓库代码到本地 本地创建有文件夹 git clone 远程仓库地址 本地文件夹名称 本地没有创建文件夹 git clone 远程仓库地址 文件夹名称 克隆完成之后,使用“cd 文件夹”的方式进 ...

  9. texshop 使用技巧

    mac osX上使用latex 的技巧 指定编译器, 通过宏定义, 也就是在文件开头, 加上类似命令 % !TEX TS-program = pdflatex 多个文件设定主文件, 通过宏定义, 加上 ...

  10. c# 之Enum--枚举

    枚举  收藏的博文连接 枚举类型声明为一组相关的符号常数定义了一个类型名称.枚举用于“多项选择”场合,就是程序运行时从编译时已经设定的固定数目的“选择”中做出决定. 枚举类型(也称为枚举):该类型可以 ...