day35
一.猴子补丁
属性在运行时的动态替换,叫做猴子补丁(Monkey Patch)
猴子补丁的用法:
1、运行时动态替换模块的方法
很多代码用到 import json,后来发现ujson性能更高,如果觉得把每个文件的import json 改成 import ujson as json成本较高,或者说想测试一下用ujson替换json是否符合预期,只需要在入口加上:
# 首先在cmd输入pip3 innstall ujson安装这个第三方模块
import json
import ujson # pip3 install ujson
def monkey_patch():
json.__name__=ujson.__name__
json.dumps=ujson.dummps
json.loads=ujson.loads
monkey_patch()
2.运行时动态增加模块的方法
总结:猴子补丁虽然能够带来一些便利,但也会搞乱代码,谨慎使用
二.内置函数
callable():括号内的对象是否是可调用的
class Foo:
pass
print(callable(Foo)) # True
chr():返回括号内整数对应的 ASCII 字符
ord():返回括号内参数对应的十进制整数(参照ASCII表)
print(chr(67)) # C
print(ord("C")) # 67
divmod(m,n):返回m/n的商和余数
print(divmod(10,3)) # (3, 1)
enumerate():将一个可遍历的数据对象(如列表、元组或字符串)组合为一个索引序列,同时列出数据和数据下标,一般用在 for 循环当中.
l={'k1':111,'k2':2222}
for i,item in enumerate(l):
print(i,item)
'''
0 k1
1 k2
'''
frozenset:冰冻集合
s1=set({1,2,3})
s1=frozenset({1,2,3})
s1.add(4)
print(s1) # AttributeError: 'frozenset' object has no attribute 'add'
globals():以字典类型返回当前位置的全部全局变量
locals():以字典类型返回当前位置的全部局部变量
def func():
x=111
print(globals())
print(locals())
func()
'''
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x000002926AA20940>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'E:/A作业/day35/02 内置函数.py', '__cached__': None, 'func': <function func at 0x000002926AD85040>}
{'x': 111}
'''
pow(x,y,z):返回x**y%z的结果
print(pow(10,2,3)) # 10 ** 2 % 3 ==> 1
slice:制定切片规则
l1 = [1, 2, 3, 4, 5, 6]
l2 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
s = slice(0, 4, 2)
print(l1[s]) # [1, 3]
print(l2[s]) # [1, 3]
zip():
将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的列表。
如果各个迭代器的元素个数不一致,则返回列表长度与最短的对象相同,利用 * 号操作符,可以将元组解压为列表。
x = "hello"
y = [111, 222, 333]
res=zip(x,y)
print(list(res)) # [('h', 111), ('e', 222), ('l', 333)]
import:用于动态加载类和函数
如果一个模块经常变化就可以使用 import() 来动态载入
m=__import__("time")
m.sleep(10)
三.垃圾回收机制
1.什么是垃圾回收机制?
垃圾回收机制(简称GC)是Python解释器自带一种机,专门用来回收不可用的变量值所占用的内存空间
2.为什么要用垃圾回收机制?
程序运行过程中会申请大量的内存空间,而对于一些无用的内存空间如果不及时清理的话会导致内存溢出,导致程序崩溃,python解释器自带垃圾回收机制来管理内存
3.储备知识
堆区与栈区
在定义变量时,变量名与变量值都是需要存储的,分别对应内存中的两块区域:堆区与栈区。
1、变量名与值内存地址的关联关系存放于栈区
2、变量值存放于堆区,内存管理回收的则是堆区的内容,
直接引用与间接引用
直接引用指的是从栈区出发直接引用到的内存地址。
间接引用指的是从栈区出发引用到堆区后,再通过进一步引用才能到达的内存地址。
l2 = [20, 30] # 列表本身被变量名l2直接引用,包含的元素被列表间接引用
x = 10 # 值10被变量名x直接引用
l1 = [x, l2] # 列表本身被变量名l1直接引用,包含的元素被列表间接引用
4.垃圾回收机制原理
垃圾回收机制的核心:引用计数
引用计数:变量值被变量名引用的次数
一个变量值的引用计数为0,才会被当做垃圾回收
引用计数的问题:
循环引用(交叉引用)==>内存泄露
循环引用会导致:值不再被任何名字关联,但是值的引用计数并不会为0,应该被回收但不能被回收
l1=['xxx']
l2=['yyy']
l1.append(l2)
l2.append(l1)
print(l1) # ['xxx', ['yyy', [...]]]
print(l2) # ['yyy', ['xxx', [...]]]
解决方案:标记清除
标记/清除算法的做法是当应用程序可用的内存空间被耗尽的时,就会停止整个程序,然后进行两项工作,第一项则是标记,第二项则是清除
#1、标记
具体地:标记的过程其实就是,遍历所有的GC Roots对象(栈区中的所有内容或者线程都可以作为GC Roots对象),
然后将所有GC Roots的对象可以直接或间接访问到的对象标记为存活的对象,
其余的均为非存活对象,应该被清除。
#2、清除
清除的过程将遍历堆中所有的对象,将没有标记的对象全部清除掉。
效率问题
基于引用计数的回收机制,每次回收内存,都需要把所有对象的引用计数都遍历一遍,这是非常消耗时间的,于是引入了分代回收来提高回收效率
解决方案:分代回收
分代回收的核心思想是:在历经多次扫描的情况下,都没有被回收的变量,gc机制就会认为,该变量是常用变量,gc对其扫描的频率会降低.
分代指的是根据存活时间来为变量划分不同等级(也就是不同的代)
四.进程
程序:就是一堆代码文件
进程:
进程是一个抽象的概念
进程指的是程序的运行过程
进程是操作系统最核心的概念
操作系统
操作系统就是一个协调、管理和控制计算机硬件资源和软件资源的控制程序
操作系统的作用
1.隐藏丑陋复杂的硬件接口,提供良好的抽象接口
2.管理,调度进程,并且将多个进程对硬件的竞争变得有序
多道技术
内存中同时存入多道(多个)程序,cpu从一个进程快速切换到另外一个,使每个进程各自运行几十或几百毫秒,这样,虽然在某一个瞬间,一个cpu只能执行一个任务,但在1秒内,cpu却可以运行多个进程,这就给人产生了并行的错觉,即伪并发,以此来区分多处理器操作系统的真正硬件并行(多个cpu共享同一个物理内存)
1.产生背景:针对单核,实现并发
ps:
现在的主机一般是多核,那么每个核都会利用多道技术
有4个cpu,运行于cpu1的某个程序遇到io阻塞,会等到io结束再重新调度,会被调度到4个
cpu中的任意一个,具体由操作系统调度算法决定。
2.空间上的复用:如内存中同时有多道程序
3.时间上的复用:复用一个cpu的时间片
强调:遇到io切,占用cpu时间过长也切,核心在于切之前将进程的状态保存下来,这样才能保证下次切换回来时,能基于上次切走的位置继续运行
空间上的复用:复用内存的空间
1.多道/个程序的代码都存入内存
2.内存空间是物理隔离的
时间上的复用:复用CPU的时间:
CPU的切换:
1.任务的运行遇到io阻塞-->提高效率
2.任务占用CPU时间过长-->(虽效率低,但可实现并发)
如果我们的核心目标是想让多个任务并发起来:那么无论是遇到IO还是没有遇到IO都应该让cpu在多个任务之间切换起来
如果我们的核心目标是想让多个任务的运行效率提升:我们应该只控制一个任务在遇到IO情况下切换到另外一个任务
小知识:
串行:一个运行完毕再运行下一个
并行:多个进程是真正意义上一起运行
并发:看起来是同时运行的,本质上还是一个个的运行