Python面试回顾

从python3.7开始,字典dict会按照键值对插入字典的顺序排序。OrderedDict的顺序是按照插入时间顺序还是键值排列顺序?OrderedDict与dict的区别是什么?OrderedDict的底层实现是什么?

OrderedDict的顺序也是按照键值对插入时间顺序来排的。这一点它与dict是一样的:
在这里插入图片描述
要说区别吧,在内置的方法上倒是有,
在这里插入图片描述
字典的popitem方法没有参数last,它不能通过设置last=False来删除第一个插入的键值对;OrderedDict可以。
另外一个区别,dict没有move_to_end方法,OrderedDict有。
在这里插入图片描述
OrderedDict在内部使用了一个双向链表来维护元素的插入顺序。当向OrderedDict中添加元素时,它会被添加到链表的尾部。当我们遍历OrderedDict时,它会按照链表中的顺序依次访问元素。

什么是全局解释器锁(GIL)

在Python中,全局解释器锁(GIL)本质上是一个互斥锁,它是在解释器(CPython)层面上的锁。Python语言设计之初,计算机广泛使用的还是单核CPU,为了解决多线程之间的数据完整与状态同步问题,最简单的方法就是加锁,每个线程在运行前都需要获取一把锁,从而保证同一时刻只能有一个线程运行,这把锁就是全局解释器锁。
GIL确保了一个进程中同一时刻只有一个线程运行,多线程在实际运行中只调用了一个CPU核心,无法使用多个CPU核心,因此多线程不能在多个CPU核心上并行,面对计算密集型的操作时,无法利用CPU的多核优势,运行效率较低。但是GIL对于单线程及I/O密集型的多线程运行没有影响。Python中的每个进程都有自己的解释器,因此多进程不受GIL的限制,可以在CPU的多个核心上并行,多进程适合计算密集型的操作,但是进程的开销较大,不适用于I/O密集型的操作。
GIL不是Python的缺陷,只是一种针对解释器的设计思想,其中使用GIL的解释器有CPython,未使用GIL的解释器有JPython。

多线程的限制以及多进程参数传递的方式

在Python中由于GIL的存在,导致进程中同一时刻只能有一个线程运行,因此,多线程无法使用多个CPU核心实现并行,只能在单一CPU核心上实现并发。面对计算密集型操作多线程无法利用CPU多核优势,运行效率较低。
多进程不受GIL的影响,可以在多个CPU核心并行。进程与线程之间的数据彼此独立,多进程传递参数时可以通过 multiprocessing.Value 或 multiprocessing.Array 方式传递。

什么是多线程竞争

进程与进程之间相互独立,每个进程都拥有自己的内存空间。线程不具有自己的内存空间,是进程的一个实例,一个进程中可以存在多个线程,这些线程共享进程的内存空间。当多个线程运行时,可能对内存空间中的资源进行抢占。例如,A、B两个人相当于两个线程,他们共用一个银行账户,银行账户中有500元,这个银行账户相当于进程内存空间中的共享资源,现在A、B同时去银行办理业务,他们看到的账户余额都是500元,A存100元,账户余额变为600元;B取出200元,账户余额变为300元。
这种情况就是发生了多线程的抢占,它们同时访问共享资源,进行操作,多线程抢占会导致数据错乱,运行结果出错。因此,为了保证线程安全,需要对共享资源加锁,保证同一时刻只有一个线程访问和操作共享资源,这样当A进行存钱时,B无法进行取钱操作,A存完钱,银行账户更新为600元后,B才能取钱,最终银行账户变为400元。

手撕代码环节

"""
设计并实现一个哈希表,提供get/set两个接口,
接口具体设计不限,哈希算法不限,哈希碰撞处理算法不限。
简单起见, key和value仅要求为整型数。
请自行提供测试用例,除基本功能外,要求涵盖哈希碰撞的情况
"""


class HashTable:
    def __init__(self, size):
        self.size = size
        self.keys = [None] * size
        self.values = [None] * size

    def _hash_function(self, key):
        # 返回的映射逻辑为取键的余数
        return key % self.size

    def _get_next_index(self, current_index):
        return (current_index + 1) % self.size

    def get(self, key):
        hash_key = self._hash_function(key)
        start_index = hash_key

        while self.keys[hash_key] is not None:
            if self.keys[hash_key] == key:
                return self.values[hash_key]

            hash_key = self._get_next_index(hash_key)

            if hash_key == start_index:
                break

    def set(self, key, value):
        hash_key = self._hash_function(key)
        start_index = hash_key

        while self.keys[hash_key] is not None and self.keys[hash_key] != key:
            hash_key = self._get_next_index(hash_key)

            if hash_key == start_index:
                raise Exception("Hash table is Full")

        self.keys[hash_key] = key
        self.values[hash_key] = value


if __name__ == "__main__":
    a = HashTable(5)
    for i in range(5):
        a.set(i + 1, i + 3)
    print("=======")
    for i in range(5):
        print(a.get(i + 1))
    print("=========")
    print(a.get(6))
    a.set(6, 1)
  • 24
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值