python 原理学习笔记

python 原理

python 的垃圾回收机制

  1. 引用计数

每个python对象都有一个核心的结构结构体PyObject, PyObject是每个对象必有的内容,其中ob_refcnt就是做为引用计数。当一个对象有新的引用时,它的ob_refcnt就会增加,当引用它的对象被删除,它的ob_refcnt就会减少。

优点:

  • 简单
  • 实时性:一旦没有引用,内存就直接释放了。不用像其他机制等到特定时机。实时性还带来一个好处:处理回收内存的时间分摊到了平时。
    缺点:
  • 维护引用计数消耗资源
  • 循环引用
  1. 分代回收

分代回收是一种以空间换时间的操作方式,Python将内存根据对象的存活时间划分为不同的集合,每个集合称为一个代,Python将内存分为了3“代”,分别为年轻代(第0代)、中年代(第1代)、老年代(第2代),他们对应的是3个链表,它们的垃圾收集频率与对象的存活时间的增大而减小。
新创建的对象都会分配在年轻代,年轻代链表的总数达到上限时,Python垃圾收集机制就会被触发,把那些可以被回收的对象回收掉,而那些不会回收的对象就会被移到中年代去,依此类推,老年代中的对象是存活时间最久的对象,甚至是存活于整个系统的生命周期内。
同时,分代回收是建立在标记清除技术基础之上。分代回收同样作为Python的辅助垃圾收集技术处理那些容器对象

如果存在循环引用的话,肯定是创建>释放数量,当创建数与释放数量的差值达到规定的阈值的时候

  1. 标记清除
  • 标记阶段,遍历所有的对象,如果是可达的(reachable),也就是还有对象引用它,那么就标记该对象为可达;
  • 清除阶段,再次遍历对象,如果发现某个对象没有标记为可达,则就将其回收

每个对象有一个gc_count的副本叫gc_ref, 对所有的gc_ref 减一,把所有gc_ref = 0 的分到unreachable 小组, 再遍历 reachable小组里的对象,把引用到的标记为reachable, 从unreachable 中拿出, 这样循环引用的两个就丢到 unreachable中,被释放了。

python 实现单例

class Singleton(object):
    _instance = None
    def __new__(cls, *args, **kwargs):
        if cls._instance is None:
            cls._instance = object.__new__(cls, *args, **kwargs)

        return cls._instance

浅拷贝和深拷贝

浅拷贝仅仅复制了容器中元素的地址
深拷贝,完全拷贝了一个副本,容器内部元素地址都不一样

python 的闭包

python中闭包从表现形式上看,如果在一个内部函数里,对在外部作用域(但不是在全局作用域)的变量进行引用,那么内部函数就被认为是闭包(closure)

def outer(x):
    def inner(y):
        return x + y
    return inner

闭包可以调用外部变量,但是无法修改,外部变量

def outer():
    s = 1
    print('outer', s)
    def inner():
        # s = s + 1 不可以修改外部变量,除非使用容器对象如 list,dict
        a = s +1
        print('inner',a)
    inner()
    return

python 中的堆栈

栈区:存储运行方法的形参、局部变量、返回值。由系统自动分配和回收。
堆区:new一个对象的引用或地址存储在栈区,指向该对象存储在堆区中的真实数据。

栈(操作系统):由操作系统自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。

堆(操作系统): 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收,分配方式倒是类似于链表。

栈使用的是一级缓存, 他们通常都是被调用时处于存储空间中,调用完毕立即释放。

堆则是存放在二级缓存中,生命周期由虚拟机的垃圾回收算法来决定(并不是一旦成为孤儿对象就能被回收)。所以调用这些对象的速度要相对来得低一些。

Flask

Flask 中请求钩子的理解?

为了让每个视图函数避免编写重复功能的代码,Flask提供了通用设施的功能,请求钩子。
请求钩子是通过装饰器的形式实现的,支持以下四种:
1.before_first_request 在处理第一个请求前运行
2.before_request:在每次请求前运行
3.after_request:如果没有未处理的异常抛出,在每次请求后运行
4.teardown_request:即使有未处理的异常抛出,在每次请求后运行

请求在flask中过程简述
  1. 创建请求上下文
  2. 创建应用上下文
  3. 把上下文压入栈
  4. 执行请求钩子 before_first_request 的相关操作
  5. 执行请求钩子 before_request 的相关操作
  6. 路由
  7. 执行请求钩子 after_request 的相关操作
  8. 执行请求钩子 teardown_request 的相关操作
  9. 把上下文弹出栈
  10. 返回响应结果

链接: 跳转

python 底层结构实现

dict 实现

entries = [
(hash(key), key , value),

]
存储的是一个连续内存,新的key-value进来, 先进行hash, 填入队友的坑。

  1. 若index下标位置已经被占用,则会判断enteies的key是否与要插入的key是否相等
  2. 如果key相等就表示key已存在,则更新value值
  3. 如果key不相等,就表示hash冲突,则会继续向下寻找空位置,一直到找到剩余空位为止
3.7 版本后,添加了一个list , 存储 index, 这样,dict 就变成有序的了。

下面为具体的实现过程:

  1. 计算key的hash值【hash(key)】,再和mask做与操作【mask=字典最小长度(IndicesDictMinSize) - 1】,运算后会得到一个数字【index】,这个index就是要插入的indices的下标位置(注:具体算法与Python版本相关,并不一定一样
  2. 得到index后,会找到indices的位置,但是此位置不是存的hash值,而是存的len(enteies),表示该值在enteies中的位置
  3. 如果出现hash冲突,则处理方式与老字典处理方式类似
python 和 GO 的 协程 区别

python

  1. 单线程内切换,适用于IO密集型程序中,可以最大化IO多路复用的效果。
  2. 无法利用多核。
  3. 协程间完全同步,不会并行。不需要考虑数据安全。
  4. 用法多样,可以用在web服务中,也可用在pipeline数据/任务消费中

Go

  1. 协程间需要保证数据安全,比如通过channel或锁。
  2. 可以利用多核并行执行。
  3. 协程间不完全同步,可以并行运行,具体要看channel的设计。
  4. 抢占式调度,可能无法实现公平
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值