总结(3)--- 知识总结(内存管理、线程阻塞、GIL锁)

一、Python中是如何进行内存管理的?

  • 垃圾回收:Python不像C++,Java等语言一样,他们可以不用事先声明变量类型而直接对变量进行赋值。对Python而言,对象的类型和内存都是在运行时确定的。这也是为什么我们称Python语言为动态类型的原因
  • 引用计数:Python采用类似Windows内核对象一样的方式来对内存进行管理。每一个对象都维护这一个对指向该对象的引用的计数。当变量呗绑定在一个对象上的时候,该变量的引用计数就是1,系统会自动维护这些标签,并定时扫描,当某标签的引用计数变为0的时候,该对就会被回收
  • 内存池机制Python的内存机制已金字塔行,1,2层主要有操作系统操作 
    • 第0层是c中的malloc,free等内存分配和释放函数进行操作
    • 第1层和第2层是内存池,有Python的接口函数PyMen——Malloc函数实现,当对象小于256K时有该层直接分配内存
    • 第3层是最上层,也就是我们队Python对象的直接操作
  • 在c中如果频繁的调用malloc 与 free时, 是会产生性能问题的,再加上频繁的分配与释放小块的内存会产生碎片,Python在这里主要干的工作有:
    • 如果请求分配的内存在1~256字节之间就使用字节的内存管理系统,否则直接使用malloc
    • 这里还是会调用malloc分配内存,但每次会分配一块大小为256K大块内存。
    • 经由内存池登记的内存到最后还是会回收到内存池,并不会调用c的free释放掉。以便下次使用。对于简单的Python对象,例如数值、字符串,元组采用的是复制的方式,也就是说当将另一个变量B赋值给变量A时,虽然A和B的内存空间仍然相同,但是当A的值发生变化时,会重新给A分配空间,A和B的地址变得不再相同

 

 

二、Python中常见的设计模式有哪些?

 

1. 创建型模式

  • 社会化的分工越来越细,自热在软件设计方面也是如此, 因此对象的创建和对象的使用分开也就成为了必然趋势,因为对象的创建会消耗系统的很多资源,所以单独对对象的创建进行研究,从而能够搞笑的创建对象就是创建型模式要探讨的问题。这里有6个具体的创建型模式可供研究,他们分别是:
    • 简单工厂模式(Simple Factory)
    • 工厂方法模式(Factory Method)
    • 抽象工厂模式(Abstract Factory)
    • 创建者模式(Builder)
    • 原型模式(Prototype)
    • 单例模式(Singleton)

          说明:严格来说,简单工厂模式不是GoF总结出来的23种设计模式之一

  • 2、结构型模式
    • 在解决了对象的创建问题之后,对象的组成以及对象之间的依赖关系就成开发人员关注的焦点,因为如何设计对象的结构,继承和依赖关系会影响到后续程序的维护性、代码的健壮性、耦合性等。对象结构的设计很容易出现设计人员水平的高低,这里有7个具体的结构型模式可供研究,他们分别是:
      • 外观模式(Facade)
      • 适配器模式(Asapter)
      • 代理模式(Proxy)
      • 装饰模式(Decorator)
      • 桥模式(Bridge)
      • 组合模式(Composite)
      • 享元模式(Flyweight)

 

  • 3.行为型模式
    • 在对象节后和对象创建问题都解决之后,就剩下对象的行为问题了,如果对象的行为设计的好,那么对象的行为会更清晰,他们之间的协作效率就会提高,这里有11个具体的行为型模式可供研究,他们分别是:
      • 模板方法模式(Template Method)
      • 观察者模式(Observer)
      • 状态模式(State)
      • 策略模式(Strategy)
      • 职责链模式(Chain of Responsibility)
      • 命令模式(Command)
      • 访问者模式(Visitor)
      • 调停者模式(Mediator)
      • 备忘录模式(Memento)
      • 迭代器模式(Iterator)
      • 解释器模式(Interpreter)

 

三、什么是线程安全?

      线程安全是在多线程的环境下,能够保证多个线程同时执行时程序依旧运行正确,而且要保证对于共享的数据可以由多个线程存取,但是同一时刻只能有一个线程进行存取。 多线程环境下解决资源竞争问题的办法是加锁来保证存取操作的唯一性

 

四、Gil锁对Python多线程的影响?

GIL的全称是Global Interpreter Lock(全局解释器锁),来源是Python设计之初的考虑,未来数据安全所做的决定。每个CPU在同一时间只执行一个线程。(在单核CPU下的多线程其实都只是并发,不是并行,并发和并行从宏观上来讲都是同时处理多路请求的概念、 但并发和并行又有区别,并行是指俩个或者多个时间在同一时刻发生;而并发是指俩个或者多个事件在同一时间间隔内发生)

在Python多线程下,每个线程的执行方式:

  1. 获取GIL
  2. 执行代码直到sleep或者是Python虚拟机将其挂起
  3. 释放GIL

可见,某个线程想要执行,必须先拿到GIL,我们可以把GIL看作是"通行证", 并且在一个Python进程中,GIL只用一个,拿不到通行证的线程,就不允许进入CPU执行

在Python2.x里,GIL的释放逻辑是当前线程遇见IO操作或者ticks技术达到100 进行释放,而且每次释放GIL锁,线程进行锁竞争、切换线程,会消耗资源。并且由于GIL锁存在,Python里一个进程永远只能同时执行一个线程(拿到GIL的线程才能执行)

IO密集型代码(文件处理、网络爬虫等) 多线程能够有效提升效率(单线程下有IO操作会进行IO等待,造成不必要的时间浪费,而开启多线程能做线程A等待时,自动切换到线程B,可以不浪费CPU资源,从而能提升程序执行效率),所以多线程对IO密集型代码比较友好     

 

五、什么是阻塞? 什么是非阻塞?

 阻塞调用时这调用结果返回之前,当前线程会被挂起。函数只有在得到结果之后才会返回。有人也许会把阻塞调用和同步调用等起来,实际上他是不同的。对于同步调用来说,很多时候当前线程还是激活的,只是从逻辑上当前函数没有返回而已,例如,我们在socket中调用receive函数,如果缓冲区中没有数据,这个函数就会一直等待,直到有数据才返回。而此时,当前线程还会继续处理各种各样的消息,如果主窗口和调用函数在同一个线程中,除非你在特殊的界面操作函数中调用,其实主界面还是应该可以刷新。socket接收数据的另一个函数recv则是一个阻塞调用的例子,当socket工作在阻塞模式的时候,如果没有数据的情况下调用该函数,则当前线程就会被挂起,直到有数据为止

非阻塞和阻塞的概念相对应,指在不能立刻得到结果之前,该函数不会阻塞当前线程,而会立刻返回

 

六、软连接和硬链接的区别?

 

软连接类似Windows的快捷方式,当删除源文件,那么软连接失效。硬链接可以理解为源文件一个别名。多个别名所代表的是一个同一个文件。rm一个文件的时候,那么此文件的硬链接数减一,当硬链接数为0的时候,文件删除

 

七、单例模式的应用场景有哪些?

 

单例模式应用的场景一般发现在一下条件下:

(1) 资源共享的情况下,避免由于资源操作时导致性能活损耗等。如日志文件,应用配置。

(2)控制资源的情况下,方便资源之间的相互通信。如线程池等。

  • 网站的计数器
  • 应用配置
  • 多线程池
  • 数据库配置,数据库连接池
  • 应用程序的日志应用

 

posted @ 2017-12-08 19:32  Dream鑫  阅读(803)  评论(2编辑  收藏  举报