热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

开发笔记:GIL,同步与异步

本文由编程笔记#小编为大家整理,主要介绍了GIL,同步与异步相关的知识,希望对你有一定的参考价值。PythonGIL1、GIL全局解释器锁
本文由编程笔记#小编为大家整理,主要介绍了GIL,同步与异步相关的知识,希望对你有一定的参考价值。

Python GIL

1、GIL全局解释器锁

2、GIL全局解释器锁VS互斥锁

3、定时器

 

1GIL全局解释器锁:

GIL全局解释器锁是一把互斥锁,都是让多个并发线程同一时间只能由一个执行

有了GIL的存在,同一进程内的多个线程同一时间只能有一个在运行,意味着在Cpython中一个进程下多个线程无法实现并行=>意味着无法利用多核优势

但不影响并发的实现

注意:保护不同的数据安全,就应该加不同的锁

为何要用GIL

因为Cpython解释器自带垃圾回收机制,并不是让线程安全的。(原因在于垃圾回收机制会将线程马上要引用值前,回收一个当前并没有绑定的值,线程后面将引用时无法查找到)(Cpython解释器的代码会收到参数,而参数是线程)

如何使用:

GIL是加在Cpython解释器之上,GIL可以比喻成执行权限,同一进程下的所有线程都是先在抢GIL,拿到执行权限,然后将代码交给解释器的代码去执行,保证python解释器同一时间只能执行一个任务的代码

 技术分享图片

2GIL全局解释器锁VS互斥锁

 技术分享图片

GIL保护的是解释器级的数据,保护用户自己的数据则需要自己加锁处理

一切都由操作系统监视,最开始所有线程抢GIL,抢到后如果没有用户设锁,那么遇到IO后,操作系统会将线程的cpu拿走,Cpython解释器释放其GIL,其他线程可以继续抢GIL执行。当前面那个被系统解放GIL的线程再次抢到GIL时,会接着上次被解放的地方继续运行下去。

如果用户有加互斥锁:

那么最开始的时候还是一样都先抢GIL全局解释器锁,抢到的运行到用户的互斥锁地方拿到锁后遇到IO会进行睡眠,此时操作系统会将GIL全局解释器锁释放,别的线程抢到遇到用户的互斥锁没法继续运行下去,因为互斥锁被睡眠的线程拿着,所以他们会被操作系统释放GIL继续抢,一直到睡眠的线程运行结束释放互斥锁后其他抢到GIL全局解释器锁的线程才可以从互斥锁地方运行下去。

(GIL相当于执行权限,会在任务无法执行的情况,被强行释放

自定义互斥锁即便时无法执行,也不会自动释放)

4、有两种并发解决方案:

多进程:计算密集型

多线程:IO密集型

计算密集型

from multiprocessing import Process
from threading import Thread
import os,time
def work1():
res
=0
for i in range(100000):
res
*=i
def work2():
res
=0
for i in range(100000):
res
*=i
def work3():
res
=0
for i in range(100000):
res
*=i
def work4():
res
=0
for i in range(100000):
res
*=i
def work5():
res
=0
for i in range(100000):
res
*=i
def work6():
res
=0
for i in range(100000):
res
*=i
def work7():
res
=0
for i in range(100000):
res
*=i
def work8():
res
=0
for i in range(100000):
res
*=i
if __name__ == __main__:
# print(os.cpu_count()) #本机为4核
start=time.time()
# p1=Process(target=work1)
# p2=Process(target=work2)
# p3=Process(target=work2)
# p4=Process(target=work2)
# p5=Process(target=work2)
# p6=Process(target=work2)
# p7=Process(target=work2)
# p8=Process(target=work2)
p1=Thread(target=work1)
p2
=Thread(target=work2)
p3
=Thread(target=work2)
p4
=Thread(target=work2)
p5
=Thread(target=work2)
p6
=Thread(target=work2)
p7
=Thread(target=work2)
p8
=Thread(target=work2)
p1.start()
p2.start()
p3.start()
p4.start()
p5.start()
p6.start()
p7.start()
p8.start()
p1.join()
p2.join()
p3.join()
p4.join()
p5.join()
p6.join()
p7.join()
p8.join()
stop
=time.time()
print("run time is %s" %(stop-start))
计算密集型 在运算简单情况下线程比进程快,但是程序中的运算都是相对
复杂,所以多进程要比多线程强

IO密集型

 

from multiprocessing import Process
from threading import Thread
import os,time
def work1():
time.sleep(
5)
def work2():
time.sleep(
5)
def work3():
time.sleep(
5)
def work4():
time.sleep(
5)
def work5():
time.sleep(
5)
def work6():
time.sleep(
5)
def work7():
time.sleep(
5)
def work8():
time.sleep(
5)
if __name__ == __main__:
# print(os.cpu_count()) #本机为4核
start=time.time()
p1
=Process(target=work1)
p2
=Process(target=work2)
p3
=Process(target=work2)
p4
=Process(target=work2)
p5
=Process(target=work2)
p6
=Process(target=work2)
p7
=Process(target=work2)
p8
=Process(target=work2)
# p1=Thread(target=work1)
# p2=Thread(target=work2)
# p3=Thread(target=work2)
# p4=Thread(target=work2)
# p5=Thread(target=work2)
# p6=Thread(target=work2)
# p7=Thread(target=work2)
# p8=Thread(target=work2)
p1.start()
p2.start()
p3.start()
p4.start()
p5.start()
p6.start()
p7.start()
p8.start()
p1.join()
p2.join()
p3.join()
p4.join()
p5.join()
p6.join()
p7.join()
p8.join()
stop
=time.time()
print("run time is %s" %(stop-start))

 

定时器

from threading import Timer,current_thread
def task(x):
print("%s run ...." %x)
print(current_thread().name)
if __name__ == __main__:
t
=Timer(3,task,args=(10,))#第一个是时间秒数,第二个是函数名,第三个是传入值
t.start()
print("")

进程优先级别:

import queue
# 队列:先进先出
q=queue.Queue(3)
q.put(
1)
q.put(
2)
q.put(
3)
print(q.get())
print(q.get())
print(q.get())
# 堆栈:先进后出
q=queue.LifoQueue()
q.put(
1)
q.put(
2)
q.put(
3)
print(q.get())
print(q.get())
print(q.get())
# 优先级队列:优先级高先出来,数字越小,优先级越高
q=queue.PriorityQueue()
q.put((
3,data1))
q.put((
-10,data2))
q.put((
11,data3))
print(q.get())
print(q.get())
print(q.get())
打印顺序:
-10
3
11

1、什么时候用池:

池的功能是限制启动的进程数或线程数,

什么时候应该限制

当并发的任务数远远超过了计算机的承受能力时,既无法一次性开启过多的进程数或者线程数时,就应该用池的概念将开启的进程数或者线程数限制在计算机可承受的范围内

2、同步vs异步

同步、异步指的是提交任务的两种方式

同步:提交完任务后就在原地等待,直到任务运行完毕后拿回到任务的返回值,再继续运行下一行代码

异步:提交完任务(绑定一个回调函数)后根本就不在原地等待,直接运行下一行代码,等到任务有返回值后会自动触发回调函数

from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor
import os
import time
import random
def task(n):
print("%s run..." %os.getpid())
time.sleep(
10)
return n**2
def parse(res):
print("...")
if __name__ == __main__:
pool
=ProcessPoolExecutor(9)#进程池默认是4,代表一次性回复个数,
# 超过回复个数,后面谁空谁回复
l=[]
for i in range(1,12):
future
= pool.submit(task,i)
l.append(future)
pool.shutdown(wait
=True)#shutdown关闭进程池入口
for future in l:
print(future.result())
print("")
要运行结束后获得结果,放在父进程中效果不够理想


技术分享图片技术分享图片

from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor
import os
import time
import random
def task(n):
print("%s run..." %os.getpid())
time.sleep(
10)
return n**2
def parse(future):
time.sleep(
1)
res
=future.result()
print("%s 处理了 %s" %(os.getpid(),res))
if __name__ == __main__:
pool
=ProcessPoolExecutor(9)#进程池默认是4,代表一次性回复个数,
# 超过回复个数,后面谁空谁回复
start=time.time()
for i in range(1,12):
future
= pool.submit(task,i)
future.add_done_callback(parse)
#parse会在futrue有返回值时立刻触发,

pool.shutdown(wait
=True)#shutdown关闭进程池入口
stop=time.time()
print("",os.getpid(),(stop-start))


优化进程

技术分享图片技术分享图片

from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor
import os
import time
import random
def task(n):
print("%s run..." %os.getpid())
time.sleep(
10)
return n**2
def parse(future):
time.sleep(
1)
res
=future.result()
print("%s 处理了 %s" %(os.getpid(),res))
if __name__ == __main__:
pool
=ThreadPoolExecutor(9)# 线程池是cpu*5个数,代表一次性回复个数,
# 超过回复个数,后面谁空谁回复
start=time.time()
for i in range(1,12):
future
= pool.submit(task,i)
future.add_done_callback(parse)
#parse会在futrue有返回值时立刻触发,

pool.shutdown(wait
=True)#shutdown关闭进程池入口
stop=time.time()
print("",os.getpid(),(stop-start))


优化线程

通过对比在有IO的情况下,线程要比进程快

 


推荐阅读
  • 深入探讨CPU虚拟化与KVM内存管理
    本文详细介绍了现代服务器架构中的CPU虚拟化技术,包括SMP、NUMA和MPP三种多处理器结构,并深入探讨了KVM的内存虚拟化机制。通过对比不同架构的特点和应用场景,帮助读者理解如何选择最适合的架构以优化性能。 ... [详细]
  • 实体映射最强工具类:MapStruct真香 ... [详细]
  • 深入解析 Apache Shiro 安全框架架构
    本文详细介绍了 Apache Shiro,一个强大且灵活的开源安全框架。Shiro 专注于简化身份验证、授权、会话管理和加密等复杂的安全操作,使开发者能够更轻松地保护应用程序。其核心目标是提供易于使用和理解的API,同时确保高度的安全性和灵活性。 ... [详细]
  • 深入解析 Spring Security 用户认证机制
    本文将详细介绍 Spring Security 中用户登录认证的核心流程,重点分析 AbstractAuthenticationProcessingFilter 和 AuthenticationManager 的工作原理。通过理解这些组件的实现,读者可以更好地掌握 Spring Security 的认证机制。 ... [详细]
  • 本文介绍了如何在多线程环境中实现异步任务的事务控制,确保任务执行的一致性和可靠性。通过使用计数器和异常标记字段,系统能够准确判断所有异步线程的执行结果,并根据结果决定是否回滚或提交事务。 ... [详细]
  • 本文探讨了如何通过预处理器开关选择不同的类实现,并解决在特定情况下遇到的链接器错误。 ... [详细]
  • 深入解析SpringMVC核心组件:DispatcherServlet的工作原理
    本文详细探讨了SpringMVC的核心组件——DispatcherServlet的运作机制,旨在帮助有一定Java和Spring基础的开发人员理解HTTP请求是如何被映射到Controller并执行的。文章将解答以下问题:1. HTTP请求如何映射到Controller;2. Controller是如何被执行的。 ... [详细]
  • Explore how Matterverse is redefining the metaverse experience, creating immersive and meaningful virtual environments that foster genuine connections and economic opportunities. ... [详细]
  • Explore a common issue encountered when implementing an OAuth 1.0a API, specifically the inability to encode null objects and how to resolve it. ... [详细]
  • 本文介绍如何使用Objective-C结合dispatch库进行并发编程,以提高素数计数任务的效率。通过对比纯C代码与引入并发机制后的代码,展示dispatch库的强大功能。 ... [详细]
  • 本文探讨了 Objective-C 中的一些重要语法特性,包括 goto 语句、块(block)的使用、访问修饰符以及属性管理等。通过实例代码和详细解释,帮助开发者更好地理解和应用这些特性。 ... [详细]
  • 从 .NET 转 Java 的自学之路:IO 流基础篇
    本文详细介绍了 Java 中的 IO 流,包括字节流和字符流的基本概念及其操作方式。探讨了如何处理不同类型的文件数据,并结合编码机制确保字符数据的正确读写。同时,文中还涵盖了装饰设计模式的应用,以及多种常见的 IO 操作实例。 ... [详细]
  • 在多线程编程环境中,线程之间共享全局变量可能导致数据竞争和不一致性。为了解决这一问题,Linux提供了线程局部存储(TLS),使每个线程可以拥有独立的变量副本,确保线程间的数据隔离与安全。 ... [详细]
  • 本文探讨了在Java多线程环境下,如何确保具有相同key值的线程能够互斥执行并按顺序输出结果。通过优化代码结构和使用线程安全的数据结构,我们解决了线程同步问题,并实现了预期的并发行为。 ... [详细]
  • FinOps 与 Serverless 的结合:破解云成本难题
    本文探讨了如何通过 FinOps 实践优化 Serverless 应用的成本管理,提出了首个 Serverless 函数总成本估计模型,并分享了多种有效的成本优化策略。 ... [详细]
author-avatar
05358
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有