python面试总结

python面试总结

(1) python中的元类(metaclass)

type()

  • 动态语言、静态语言的最大不同:
    创建函数和类,不再编译时定义的,而是在运行时动态创建。

  • type():
    查看一个对象的类型
    又可创建出新的类(创建class的方法就是type()函数)

  • 创建一个class对象,type()函数需要传入三个参数:
    类名 = type(‘类名’, (继承的父类, ), dict(方法名=fn))
    Hello = type(‘Hello’, (object,), dict(hello=fn))

  • type()函数创建类和直接写class是完全一样的,Python解释器遇到class定义时,仅仅是扫描一下class定义的语法,然后调用type()函数创建出class。

metaclass

  • metaclass: 元类, 控制类的创建行为
  • 先定义metaclass,就可以创建类,然后创建实例。
  • metaclass允许创建类、修改类,即: 可把类看成metaclass的实例

ORM (Obejct Relational Mapping)

  • ORM:对象关系映射,即:关系数据库:关系数据库的一行映射为一个对象,也就是一个类对应一个表

(2) 类方法和静态方法

  • 类方法:将类本身作为对象进行操作的方法。
class Foo:
    @classmethod
    def class_method(cls):
        pass
Foo.classs_method()
  • 静态方法:不需要实例化就可以由类执行的方法
class Foo:
    @staticmethod
    def static_method():
        pass
Foo.static_method()
  • 类、类的所有方法以及类变量在内存中只有一份,所有的实例共享它们。而每一个实例都在内存中独立的保存自己和自己的实例变量。

面向对象基本概念

  • 类(Class): 用来描述具有相同属性和方法的对象(实例)的集合。
  • 实例:也称对象。通过类定义的初始化方法,赋予具体的值,成为一个”有血有肉的实体”。
  • 实例化:创建类的实例的过程或操作。
  • 实例变量:定义在实例中的变量,只作用于当前实例。
  • 类变量:类变量是所有实例公有的变量。类变量定义在类中,但在方法体之外。
  • 数据成员:类变量、实例变量、方法、类方法、静态方法和属性等的统称。
  • 方法:类中定义的函数。
  • 静态方法:不需要实例化就可以由类执行的方法
  • 类方法:类方法是将类本身作为对象进行操作的方法。
  • 方法重写:如果从父类继承的方法不能满足子类的需求,可以对父类的方法进行改写,这个过程也称override。
  • 封装:将内部实现包裹起来,对外透明,提供api接口进行调用的机制
  • 继承:即一个派生类(derived class)继承父类(base class)的变量和方法。
  • 多态:根据对象类型的不同以不同的方式进行处理。

python自省(reflect反射)

  • getattr()、hasattr()、delattr()和setattr()较为全面的实现了基于字符串的反射机制。
# commons.py  视图文件

def login():
    print("这是一个登陆页面!")

def logout():
    print("这是一个退出页面!")

def home():
    print("这是网站主页面!")
#visit.py 
import commons 

def run():
    inp = input("请输入您想访问页面的url:  ").strip()
    if hasattr(commons,inp):
        #从commons模块里查找和inp字符串‘外形’相同的函数名,并将其返回
        #getattr(类或模块,'字符串')
        func = getattr(commons,inp)
        func() 

if __name__ == '__main__':
    run()

动态导入模块

  • import(字符串参数) 类似getattr()的反射功能
  • import()方法会根据字符串参数,动态导入模块名
#visit.py 
def run():
    inp = input("请输入您想访问页面的url:  ").strip()
    modules, func = inp.split("/")
    #跨包导入问题 假设'view'是另一个包名
    obj = __import__('view.'+modules, fromlist=True)
    if hasattr(commons,func):
        #从commons模块里查找和inp字符串‘外形’相同的函数名,并将其返回
        #getattr(类或模块,'字符串')
        func = getattr(commons,func)
        func() 

if __name__ == '__main__':
    run()

(3) 推导式

  • 列表推导式:
    res1 = [x * x for x in range(1, 10)]
    dic = {“k1”:”v1”,”k2”:”v2”}
    res = [i+’:’j for i, j in dic.items()]
  • 字典推导式
    {i:i**i for i in range(1,5)}
  • 集合推导式
    {i for i in ‘abcdefgh’ if i not in ‘def’}
  • 面试题
    result = [lambda x: x + i for i in range(10)]
    print(result0) #19

result = [lambda x,i = i: x+i for i in range(10)]
print(result0) #10


(4)Python中单下划线和双下划线

  • __实例变量中,如果以__开头就变成了私有变量,只能内部访问,外部不可以访问。__name python内部机制原理—-> _类名__name
  • 确保了外部代码不能修改对象内部的状态,这样通过访问限制,使代码更加键壮。

  • 总结:
  • name、_namename_:建议私有变量,不要在外部访问。
  • _name、 __name:强制的私有变量,但也可在外部危险访问。
  • name:特殊变量,与私有性质无关,例如doc
  • name_、name__:没有任何特殊性,普通的标识符,最好不要这么起名。

(5) 字符串格式化 % 和 .format()

  • %:只能一个一个的进行传参
  • .format():可以使用位置传参、可变参数传参,关键字参数传参,

(6) 生成器(generator)和迭代器(Iterator)

  • 生成器:(和list相比, 节省大量的内存和空间)
    1、一边循环一边计算的机制,称为生成器 generator
    2、使用yield返回的函数会变成一个生成器(generator)
    g = (x*x for x in range(10)) 返回的g是一个生成器对象
    可以通过next(g)获得下一个返回值
    生成器都是Iterator对象.
# 斐波那契
def fib(n):
    i, a, b = 0, 0, 1
    while i < n:
        yield b
        a, b = b, a+b
        i += 1

res =list(fib(10))

  • 迭代器 (实现迭代器需要两个方法: next()和iter() )
    凡是可作用于for循环的对象都是Iterable类型;
    凡是可作用于next()函数的对象都是Iterator类型,它们表示一个惰性计算的序列;
    集合数据类型如list、dict、str等是Iterable但不是Iterator,不过可以通过iter()函数获得一个Iterator对象。

  • 为什么list、dict、str等数据类型不是Iterator?
    这是因为Python的Iterator对象表示的是一个数据流,Iterator对象可以被next()函数调用并不断返回下一个数据,直到没有数据时抛出StopIteration错误。可以把这个数据流看做是一个有序序列,但我们却不能提前知道序列的长度,只能不断通过next()函数实现按需计算下一个数据,所以Iterator的计算是惰性的,只有在需要返回下一个数据时它才会计算。

(6)*args 和 **kwargs

  • *args和**kwargs都是动态参数,放在位参和默参之后

  • *args:表示接受任意个参数,即可变参数
    调用时,会将实参打包成一个元组传给形参
    若参数是列表,使用一个*号可以将列表内部元素逐一作为参数,传给函数。

  • **kwargs:表示接受键值对的动态参数,数量任意。即关键字参数
    调用时,会将实参打包成字典传给形参。
    若参数是字典,使用两个*号,将字典中key-value用将逐一作为参数,传给函数。

  • *args和**kwargs组合
    万能参数,接受任何形式和任意数量的参数。
def func(*args, **kwargs):
    pass

  • **extra表示把extra这个dict的所有key-value用关键字参数传入到函数的**kw参数,kw将获得一个dict,注意kw获得的dict是extra的一份拷贝,对kw的改动不会影响到函数外的extra

  • 命名关键字参数
def person(name, age, *args, city, job): #限制关键字参数的名字city,job
    print(name, age, args, city, job)

(7)面向切面编程AOP和装饰器

  • 面向切面编程AOP:在运行时,动态地将代码切入到类的指定方法、指定位置上的编程思想就是面向切面的编程。

  • 装饰器:在代码运行期间动态增加功能的方式,称之为“装饰器”(Decorator),强调开放封闭原则(代码复用,不破坏代码结构)
  • 使用场景:插入日志、性能测试
import functools
import time
def log(text):
    def decorator(func):
        @functools.wraps(func) #将原始函数的某些属性更新到包裹函数
        def wrapper(*args, **kwargs):
            start_time = time.time()
            func(*args, **kwargs)
            print(time.time() - start_time)
        return wrapper
    return decorator

@log('execute')
def now():
    print('2018-1-1')

if __name__ == '__main__':
    now()

(8)鸭子类型

  • 动态语言调用实例方法时不检查类型,只要方法存在,参数正确,就可以调用。

(9)python中重载

  • 函数重载主要是为了解决两个问题。
    可变参数类型。(python接受任意类型的参数)
    可变参数个数。(可变参数*args)
  • python自然不需要重载

(10)新式类和旧式类

  • 旧式类py2:A继承B,B若无继承object,B没有object
  • 新式类py3:默认继承object

  • 深度优先:py2.2以前DFS
    A - B - D
    A - C - E
    A-B-D-C-E
  • 广度优先:BFS
    A - B - D
    A - C - D
    A-B-C-D
    广度优先不适用于:
    A - B - D
    A - C - E
  • py2.3—至今: c3算法
  • 查看属性查找顺序:print(A.__mro__)

(11) __new__和init的区别

  • __new__是一个静态方法,__init__是一个实例方法
  • __new__方法会返回一个创建的实例,而__init__什么都不返回.
  • __new__返回一个cls的实例时__init__才会被调用
  • 当创建一个新实例时调用__new__,初始化一个实例时用__init__

(12) 单例模式

  • 确保某个类只有一个实例
#使用__new__方法
class Singleton(object):
   def __new__(cls, *args, **kw):
        if not hasattr(cls, '_instance'):
            orig = Super(Singleton, cls)
            cls._instance = orig.__new__(cls, *args, **kw)
        return cls._instance
class MyClass(Singleton):
    pass

#共享属性   
class Singleton(object):
    _state = {}
    def __new__(cls, *args, **kw):
        orig = super(Singleton, cls).__new__(cls, *args, **kw)
        orig.__dict__ = cls._state
        retur orig
class MyClass(Singleton):
    pass

#装饰器版本
def Singleton(cls):
    instances = {}
    def getinstance(*args, **kw):
        if cls not in instances:
            instances[cls] = cls(*args, **kw)
        return instances[cls]
    return getinstance

@Singleton
class MyClass:
    pass

(13) python中的变量作用域

  • 作用域指的是变量的作用范围

  • L(Local) 局部作用域
  • E (Enclosing) 闭包函数外的函数中
  • G (Global) 全局作用域
  • B (Built-in) 内建作用域

  • nonlocal关键字!它可以修改嵌套作用域(enclosing作用域,外层非全局作用域)中的变量
  • Python函数的作用域取决于其函数代码块在整体代码中的位置,而不是调用时机的位置。

(14)GIL线程全局锁

  • GIL:任何python线程执行前,必须先获得GIL锁,每执行100条字节码,解释器就自动释放GIL锁,让别的线程有机会执行。
  • GIL全局锁:实际上把所有的线程都加了锁,多线程在python中只能交替执行,即只能用到一个核。

(15)协程

  • 协程编码模式脱离不了三个模式: 事件循环 + 回调(驱动生成器) + epoll(IO多路复用) asynico是python用于解决异步io编程的一整套方案

  • Python中我们进行并发编程:
    CPU密集型任务: 多进程
    IO密集型人物: 多线程/协程

  • 协程:是运行在单线程中的“并发”,协程相比多线程的一大优势就是省去了多线程之间的切换开销,获得了更高的运行效率。python中的异步IO模块asyncio就是协程模块。

  • 利用多核cpu
    多进程+协程,既充分利用多核,又充分发挥协程的高效率,可获得极高的性能。

  • 进程/线程:操作系统提供的一种并发处理任务的能力
  • 协程:程序员通过高超的编码能力,在代码执行流程中人为的实现多任务并发,是单个线程内的任务调度技巧。

(16)闭包

  • 闭包 = 内嵌函数 + 环境变量(内嵌函数定义时外部的变量)
  • 保存闭包现场 , 记忆上次调用的状态
def curve_pre():
    a = 25 #环境变量
    def curve(x): #1内嵌函数
        return a*x*x   #2内嵌函数引用环境变量
    return curve #3外部返回内嵌函数

(17) lambda 函数

  • 关键字lambda就是匿名函数,表达式的结果就是其返回值
  • 优点:简便 节省字义空间 匿名函数没有名字,避免函数名冲突。
    可以作为别的函数的返回值

(18) 函数式编程

  • 函数式编程特点: 允许把函数本身作为参数传入另一个函数,还允许返回一个函数。

  • map(func, Iterable) 返回一个Iterator 惰性序列,通过list()计算
  • map将传入的函数依次作用到序列的每个元素
  • list(map(str, [1, 2, 3, 4, 5, 6, 7, 8, 9]))

  • reduce把一个函数作用在一个序列[x1, x2, x3, …]上,这个函数必须接收两个参数,reduce把结果继续和序列的下一个元素做累积计算

  • filter()把传入的函数依次作用于每个元素,然后根据返回值是True还是False决定保留还是丢弃该元素。
li = [11,22,33,44,55]
result = filter(lambda x: x>33,li)
print(list(result)

  • sorted([], key= , reverse= )
    排序:返回一个排好序的新列表
    sort() 就地改变原列表

(19)python中的深拷贝和浅拷贝

  • 深拷贝和浅拷贝、赋值分为两部分
  • 1 数字和字符串: 深 浅拷贝 赋值都一样,因为都是指向同一个地址
  • 2 字典 元组 列表
只是创建一个变量,指向原来的地址
浅拷贝: 内存中只额外创建第一层数据
import copy
v1 = {'k1': 1, 'k2': 2, 'k3': [1,2,3]}
v2 = copy.copy(v1)
id(v1['k1'])和id(v2['k1']) 地址一致

----------------------------
深拷贝:将所有的数据从新备份
v3 = copy.deepcopy(v1)
id(v1['k1'])和id(v2['k1']) 地址不一致
id(v1['k3'][0])和id(v2['k3'][0])地址一致  python内部字符串 数字优化

(20)python的垃圾回收机制

  • python GC主要使用引用计数来跟踪和回收垃圾
    pyObject是每个对象必有的内容,ob_refcnt作为引用计数,当一个对象有新的引用时,就会增加,对象删除,ob_refcnt就会减少
    优点:
    1、简单
    2、实时性 一旦没有引用,内存就直接释放。
    缺点:
    1、消耗资源
    2、循环引用

  • 在引用计数的基础上,通过标记-清除解决容器对象产生的循环引用问题
    按需分配,等到没有空闲内存的时候从寄存器和程序栈上的引用出发,遍历以对象为节点,以引用为边构成的图,把所有可以访问的对象都打上标记,然后清扫一遍内存空间,把没有标记的对象释放。

  • 通过分代回收时间换空间方法提高垃圾回收效率
    系统中的所有内存块根据其存活时间划分为不同的集合,每个集合就成为一个“代”,垃圾收集频率随着“代”的存活时间的增大而减小,存活时间通常利用经过几次垃圾回收来度量。
    Python默认定义了三代对象集合,索引数越大,对象存活时间越长。

  • 三种情况会触发垃圾回收
    1、调用gc.collect()
    2、当gc模块的计数器达到阀值
    3、程序退出的时候

(21) List

  • list:一个有序可重复的元素集合
  • 常用操作:
    lis = [1, 2, 3]
    del lis
    lis.remove(1)
    lis.pop()
    lis.append()
    lis.extend()
    insert(index, obj)
    reverse()
    lis.clear()
  • 常用函数:
    len(list)
    max(list)
    min(list)
    list(seq) #将序列转为列表
    切片: list[start:stop:step]

  • 将列表当做堆栈(后进先出)
    将列表的表头作为堆栈底部,表尾作为堆栈顶部
    用append()方法把一个元素添加到堆栈顶部
    用pop()方法把一个元素从堆栈顶释放(从列表尾部弹出一个元素)
  • 列表在内存内部是顺序存储结构的,所以在其尾部的添加和删除动作,也就是append和pop方法的效率非常高,具备随机存取速度,也就是O(1)的时间复杂度

  • 将列表当做队列(先进先出)效率不高
    队列是一种先进先出的数据结构。但是用Python的列表做队列的效率并不高。因为,虽然在列表的最后添加或者弹出元素速度很快,但在列头部弹出第一个元素的速度却不快(因为所有其他的元素都得跟着一个一个地往左移动一位)
  • 通常:queue.Queue作为单向队列,使用collections.deque作为双向队列

(21) is 和 ==

  • python对象包含三个基本要素id(内存地址), type(数据类型), value
  • is (同一性运算符) 判断因素 id(内存地址)
  • == (比较运算符) 判断因素 value(值)

(22) python2 和Python3的区别

  • 1 print特殊语句 print()函数
  • 2 raw_input(读取非字符类型) input()
  • 3 xrange() range()
  • 4 map() zip() filter() 返回列表 python3 返回一个迭代器
  • 5 / py2结果是整除, py3是浮点型
  • 6 python2中默认的字符串类型默认是ASCII,python3中默认的字符串类型是Unicode。

(23)read() readline()和readlines()

  • f.read(size): 读取一定大小的数据,然后作为字符串或字节对象返回(注意文件大小,太大的话,加上size,不然内存就爆了)
  • f.readline():每次读取一行内容。
  • f.readlines(): readlines()一次读取所有内容并按行返回list
    如果是配置文件,调用readlines()

(24) super()

  • super(子类名,self).方法名()
  • 常见super调用父类的实例化方法__init__
    super(Father, self).__init__(name=name,age=age)

操作系统

(25)IO多路复用

  • IO驱动的模型:
    1)阻塞IO
    2)非阻塞IO
    3)IO复用(select和poll)
    4)信号驱动IO(sigio)
    5)异步IO(aio_)

  • IO多路复用:指内核一旦发现进程指定的一个或者多个IO条件准备读取,内核就通知该进程。

  • 与多进程和多线程技术相比,I/O多路复用技术最大的优势:系统开销小。系统不必创建进程/线程,也不必维护进程/线程。

  • I/O多路复用的系统调用有select poll epoll
  • I/O多路复用就是通过一种机制,一个线程可以监视多个描述符,一旦描述符就绪(一般是读就绪或写就绪),能通知程序进行相应的读写操作。

(1) select

  • select监视的文件描述符号分3类,(writefds, readfds, exceptfds),程序启动后select函数会阻塞,直到有描述符就绪(有数据可读、可写或者有except)、或者超时(timeout指定等待时间,如果立即返回设为null即可),函数返回,当select返回后,可以通过遍历fd_set,来找到就绪的描述符。

  • 特点:
  • 1、select最大缺陷:单个进程所打开的FD有一定限制。它由FD_SETSIZE设置,默认值1024.
  • 2、对socket进行扫描时是线性扫描,即采用轮询的方法,效率较低。
  • 3、需要维护一个用来存放大量fd的数据结构,这样使得用户空间和内核空间在传递该结构时复制开销大;

(2)poll

  • poll:它将用户传入的数组拷贝到内核空间,然后查询每个fd对应的设备状态,如果设备就绪则在设备等待队列中加入一项并继续遍历,如果遍历完所有fd后没有发现就绪设备,则挂起当前进程,知道有设备就绪或超时,被唤醒后它又要再次遍历pollfd,这个过程经历了多次无畏的遍历。

  • 特点:
  • 1、没有最大连接数限制,原因是它是基于链表来存储的.

  • 缺点:
    1、大量的fd的数组被整体复制于用户态和内核地址空间之间。而不管这样的复制是否有意义。
    2、poll还有一个特点:‘水平触发’,如果报告了fd后,没有被处理,那么下次poll时会再次报告该fd。

(3)epoll

  • epoll支持水平触发和边缘触发,最大特点在于边缘触发,它告诉进程哪些fd刚刚变为就绪态,并且只会通知一次。还有一个特点,epoll使用‘事件’的就绪通知方式,通过epoll_ct注册fd,一旦该fd就绪,内核就会采用类似callback的回调机制来激活该fd,epoll_wait便可以收到通知。

  • epoll的优点
  • 1 没有最大的并发连接限制
  • 2 效率提升,不管是轮询的方式,不会随着FD数目的增加效率下降,只有活跃可用的FD才会调用callback函数,即epoll最大的优点就在于它只管你‘活跃’的连接,而跟连接总数无关,因此在实际的网络环境中,Epoll的效率会远远高于select和poll。
  • 3 内存拷贝 利用mmap()文件映射内存加速与内核空间的消息传递,即:epoll使用mmap减少复制开销。

(3)边沿触发和水平触发

  • 水平触发: 如果文件描述符已经就绪可以非阻塞的执行IO操作了,此时会触发通知.允许在任意时刻重复检测IO的状态,没有必要每次描述符就绪后尽可能多的执行IO.select,poll就属于水平触发.
  • 边缘触发: 如果文件描述符自上次状态改变后有新的IO活动到来,此时会触发通知.在收到一个IO事件通知后要尽可能多的执行IO操作,因为如果在一次通知中没有执行完IO那么就需要等到下一次新的IO活动到来才能获取到就绪的描述符.信号驱动式IO就属于边缘触发.

  • 总结:
  • (1)select、poll实现需要遍历整个fd集合,而epoll只要判断一下就绪链表是否为空就行了,这节省了大量的CPU时间。这就是回调机制带来的性能提升。
  • (2)select,poll每次调用都要把fd集合从用户态往内核态拷贝一次,并且要把current(当前进程)往设备等待队列中挂一次,而epoll只要一次拷贝,而且把current往等待队列(epoll内部队列,不是设备等待队列)上挂也只挂一次。这也能节省不少的开销。
  • (3)在select/poll中,进程只有在调用一定的方法后,内核才对所有监视的文件描述符进行扫描,而epoll事先通过epoll_ctl()来注册一个文件描述符,一旦基于某个文件描述符就绪时,内核会采用类似callback的回调机制,迅速激活这个文件描述符,当进程调用epoll_wait()时便得到通知。(此处去掉了遍历文件描述符,而是通过监听回调的的机制。这正是epoll的魅力所在。)

(26)常见的调度算法总结 原文地址

  • 调度算法:根据系统的资源分配策略所规定的资源分配算法

  • 先来先服务(FCFS)
    适用于:cpu繁忙型作业 不利于I/O繁忙型的作业(进程)

  • 短作业(进程)优先调度算法
    短作业(进程)优先调度算法(SJ/PF)是指对短作业或短进程优先调度的算法,该算法既可用于作业调度, 也可用于进程调度。但其对长作业不利;不能保证紧迫性作业(进程)被及时处理;作业的长短只是被估算出来的。

  • 最高优先权调度算法(FPF)
    为了照顾紧迫性作业,使之进入系统后便获得优先处理,引入了最高优先权优先(FPF)调度算法。 此算法常被用在批处理系统中,作为作业调度算法,也作为多种操作系统中的进程调度,还可以用于实时系统中。当其用于作业调度, 将后备队列中若干个优先权最高的作业装入内存。当其用于进程调度时,把处理机分配给就绪队列中优先权最高的进程,此时, 又可以进一步把该算法分成以下两种:
    1)非抢占式优先权算法
    2)抢占式优先权调度算法(高性能计算机操作系统)
    1. 优先权类型 。
      对于最高优先权优先调度算法,其核心在于:它是使用静态优先权还是动态优先权, 以及如何确定进程的优先权。
      3.动态优先权
      高响应比优先调度算法为了弥补短作业优先算法的不足,我们引入动态优先权,使作业的优先等级随着等待时间的增加而以速率a提高。 该优先权变化规律可描述为:优先权=(等待时间+要求服务时间)/要求服务时间;即 =(响应时间)/要求服务时间

  • 时间片轮转法。
    时间片轮转法一般用于进程调度,每次调度,把CPU分配队首进程,并令其执行一个时间片。 当执行的时间片用完时,由一个记时器发出一个时钟中断请求,该进程被停止,并被送往就绪队列末尾;依次循环。

  • 多级反馈队列调度算法
    多级反馈队列调度算法多级反馈队列调度算法,不必事先知道各种进程所需要执行的时间,它是目前被公认的一种较好的进程调度算法。
  • 实施过程:
    1) 设置多个就绪队列,并为各个队列赋予不同的优先级。在优先权越高的队列中, 为每个进程所规定的执行时间片就越小。
    2) 当一个新进程进入内存后,首先放入第一队列的末尾,按FCFS原则排队等候调度。 如果他能在一个时间片中完成,便可撤离;如果未完成,就转入第二队列的末尾,在同样等待调度…… 如此下去,当一个长作业(进程)从第一队列依次将到第n队列(最后队列)后,便按第n队列时间片轮转运行。
    3) 仅当第一队列空闲时,调度程序才调度第二队列中的进程运行;
    仅当第1到第( i-1 )队列空时, 才会调度第i队列中的进程运行,并执行相应的时间片轮转。
    4) 如果处理机正在处理第i队列中某进程,又有新进程进入优先权较高的队列, 则此新队列抢占正在运行的处理机,并把正在运行的进程放在第i队列的队尾。

(26) 死锁

  • 死锁: 是指多个进程因竞争资源而造成的一种僵局,若无外力作用,这些进程都将无法向前推进。

  • 死锁产生原因:
    1 系统资源竞争
    2 进程推进顺序非法

  • 死锁产生的必要条件
    1 互斥条件: 进程要求对所分配的资源进行排他性控制,一段时间内某资源仅为一个进程所占用,其他请求进程只能等待。
    2 不剥夺条件: 进程所获得的资源在未使用完毕之前,不能被其他进程强行夺走,即只能由获得该资源的进程自己来释放。
    3 请求保持条件: 进程已经保持了至少一个资源,但又提出了新的资源请求,而该请求已被其他进程占有,此时请求进程被阻塞,但对自己已获得的资源保持不放。
    4 循环等待条件: 存在一种进程资源的循环等待链,链中每一个进程已获得的资源同时被链中下一个进程所请求。

  • 处理死锁的方法
    1 预防死锁,防止系统进入不安全状态
    2 银行家算法
    3 检测死锁(资源分配图)
    4 死锁解除的主要方法:资源剥夺法 进程撤销法 进程回退法

(27) 程序编译与链接

  • Bulid过程可以分解为4个步骤:预处理(Prepressing), 编译(Compilation)、汇编(Assembly)、链接(Linking)

(28) 虚拟内存技术

  • 这种存储器实际上并不存在,只是由于系统提供了部分装入、请求调入和置换功能后,给用户的感觉是好像存在一个比实际物理内存大得多的存储器.
    (多次性 对换性 虚拟性)
  • 虚拟内存的实现有以下三种方式:
    l 请求分页存储管理
    l 请求分段存储管理
    l 请求段页式存储管理

  • 分页和分段
    分页: 用户程序的地址空间被划分成若干固定大小的区域,称为“页”
    分段: 将用户程序地址空间分成若干个大小不等的段,每段可以定义一组相对完整的逻辑信息。

  • 分页与分段区别
  • 分页:页是信息的物理单位,分页是为了实现离散分配方式,以消减内存的外零头,提高内存的利用率。或者说,分页仅仅是由于系统管理的需要不是用户的需要。
  • 分段:段是信息的逻辑单位,它含有一组其意义相对完整的信息,分段的目的是为了能更好的满足用户的需要。

  • 页面置换算法
    最佳置换算法OPT:不可能实现
    先进先出FIFO
    最近最久未使用算法LRU:最近一段时间里最久没有使用过的页面予以置换.

clock算法

  • 16
    点赞
  • 117
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值