🌙
交互式练习

LLM 练习 005

34 道题 · 选择题 + 填空题 + 简答题 + 代码实战 · 即时反馈 · 记录保存
← 返回主页
客观题
0/20
主观题
0/14
做题记录

做题记录

    暂无记录

    答题详情

    一、单选题(10 题)
    第 1 题单选题
    在 Python 中,线程相对进程,更准确的描述是( )。
    A 线程是资源分配的基本单位
    B 线程是 CPU 调度的基本单位,依附于进程存在
    C 线程可以脱离进程单独运行
    D 进程与线程都不共享内存
    第 2 题单选题
    创建并启动子线程的正确三步不包含( )。
    A import threading
    B threading.Thread(target=func, ...)
    C 线程对象.start()
    D threading.spawn(func)
    第 3 题单选题
    关于 Threadtarget 参数,正确的是( )。
    A 应写成 target=func()
    B 应写成 target=func
    C target 必须是 lambda
    D target 只能是字符串函数名
    第 4 题单选题
    只有一个参数的任务函数,使用 args 传参时应写成( )。
    A args=(5)
    B args=(5,)
    C args=5
    D args=[5]
    第 5 题单选题
    同一进程内多个线程对全局列表执行 append,一般( )。
    A 不需要也不应该共享
    B 可以共享,能看到同一份列表
    C 每个线程有独立副本
    D 必须先 fork 才能共享
    第 6 题单选题
    多个线程并发对同一整型全局变量做 count = count + 1 可能出现结果小于理论值,主要是因为( )。
    A Python 版本太低
    B +1 非原子操作,存在调度交错导致丢更新
    C global 写多了
    D 线程不能访问全局变量
    第 7 题单选题
    互斥锁的典型用法正确的是( )。
    A 每个线程各自 threading.Lock() 一把新锁
    B 多个线程共用同一把 Lock 对象,在临界区 acquire/release 或用 with lock:
    C 上锁后不必释放
    D Lock 只能用于进程
    第 8 题单选题
    CPython 中的 GIL 主要指( )。
    A 用户创建的 threading.Lock
    B 解释器层的全局锁,同一时刻通常只有一个线程执行 Python 字节码
    C 网络全局 IP
    D 生成器的全局变量
    第 9 题单选题
    下列能得到一个生成器对象的是( )。
    A g = [i for i in range(3)]
    B g = (i for i in range(3))
    C g = {i for i in range(3)}
    D g = list(range(3))
    第 10 题单选题
    关于 async / awaitasyncio.run,正确的是( )。
    A async def 定义的函数一调用就会执行完
    B await 用于等待可等待对象并把控制权交回事件循环
    C asyncio.run 可以在任意嵌套函数里随意连续调用
    D 协程运行在独立进程里
    二、填空题(10 题)
    第 11 题填空题
    进程是操作系统分配的基本单位;线程是调度的基本单位。
    第 12 题填空题
    创建线程类:threading.Thread(target=, args=..., kwargs=...)
    第 13 题填空题
    主线程默认会等待所有线程结束后再结束进程(常规情况)。
    第 14 题填空题
    若希望主线程结束时子线程不再继续执行,可设置线程(daemon=True)。
    第 15 题填空题
    线程之间与进程相比,之间默认共享进程内全局数据;进程之间默认共享。
    第 16 题填空题
    互斥锁对象的创建方式常为 lock = threading.()
    第 17 题填空题
    yield 的函数称为生成器函数,调用该函数得到的是
    第 18 题填空题
    生成器耗尽后再 next,会抛出异常;for 遍历时会自动处理。
    第 19 题填空题
    协程三要素:async def、顶层常用 asyncio.run(...)
    第 20 题填空题
    在同一协程函数里要并发执行多个协程,常用 asyncio. 包装成任务。
    三、简答题(7 题)
    第 21 题简答题
    进程与线程是什么关系?为什么说"没有进程就没有线程"?
    查看参考答案 ▼
    线程必须依附在进程里运行:进程向操作系统申请地址空间、文件描述符等资源,线程是在该进程内部被调度执行的执行流。没有进程作为"容器"和资源边界,线程无法单独存在,因此说没有进程就没有线程。
    第 22 题简答题
    为什么多线程执行时,打印顺序可能每次运行都不一样?
    查看参考答案 ▼
    多个线程谁先获得 CPU、执行到哪一行,由操作系统和解释器的调度策略决定,不是代码书写顺序保证的。因此并发时输出顺序不确定属正常现象。
    第 23 题简答题
    线程之间共享全局变量与进程之间不共享,区别的原因是什么?
    查看参考答案 ▼
    同一进程内的线程共用同一地址空间,全局变量在同进程内只有一份;而每个进程有独立的虚拟地址空间,子进程是父进程内存的拷贝,因此各进程的全局变量互不天然共享。
    第 24 题简答题
    互斥锁要解决什么问题?使用 with lock: 有什么好处?
    查看参考答案 ▼
    互斥锁用于线程同步,保证同一时刻只有一个线程进入临界区操作共享数据,避免"读—改—写"被抢占导致的数据竞争。with lock: 在离开代码块时自动释放锁,减少忘记 release() 造成的死锁问题。
    第 25 题简答题
    简要说明 GIL 与 threading.Lock 的区别;为什么在 CPython 里有时仍要给共享数据加 Lock?
    查看参考答案 ▼
    GIL 是 CPython 解释器层的全局解释器锁,限制同一时刻通常只有一条线程在执行 Python 字节码。threading.Lock 是程序员为保护自己共享数据创建的显式锁。即使有 GIL,一条源码语句可能对应多条字节码,线程仍可能在中间被切换,因此业务上的非原子更新仍可能出错。
    第 26 题简答题
    生成器相对一次性构造完整列表,主要优点是什么?yieldreturn 在生成器函数中的典型区别?
    查看参考答案 ▼
    生成器按需产出元素,不一次性把所有结果放进内存,节省内存yield暂停当前函数、向外产出一个值,下次从暂停处继续;return 用于结束生成器函数(结束迭代)。
    第 27 题简答题
    协程三要素是什么?asyncio.runasyncio.create_task 分别适合什么场景?
    查看参考答案 ▼
    三要素:async def 定义协程函数、await 等待可等待对象、asyncio.run 启动事件循环。asyncio.run 常用于最外层启动整个异步程序;在同一 async def 里要对多个协程并发时,用 create_task 将协程包装为任务。
    四、代码实战(7 题)
    第 28 题代码实战
    多线程入门(必做)
    定义两个无参任务函数(如模拟"写代码""听音乐"打印若干行)。
    创建两个 threading.Thread,指定 target,调用 start()
    观察多次运行输出顺序是否可能不同。
    查看参考答案 ▼
    import threading def coding(): for i in range(3): print("coding", i) def music(): for i in range(3): print("music", i) t1 = threading.Thread(target=coding) t2 = threading.Thread(target=music) t1.start() t2.start()
    第 29 题代码实战
    线程传参(必做)
    使用 args=('小明', 3) 按位置传参。
    使用 kwargs={...} 按关键字传参。
    说明 args 单元素必须加逗号的原因(注释)。
    查看参考答案 ▼
    def greet(name, times): for i in range(times): print(name, i) def show(**kwargs): print(kwargs) t1 = threading.Thread(target=greet, args=("小明", 3)) t2 = threading.Thread(target=show, kwargs={"a": 1, "b": 2}) t1.start() t2.start() # 单元素元组: args=(5,) 不能写成 args=(5)
    第 30 题代码实战
    全局变量与互斥锁(重点必做)
    定义全局整型 count = 0,两个线程各循环较大次数(如 10 万次)执行 count += 1
    先不加锁运行,观察结果是否小于预期。
    再用同一把 threading.Lock 包裹临界区。
    查看参考答案 ▼
    import threading count = 0 lock = threading.Lock() N = 100000 def add(): global count for _ in range(N): with lock: count += 1 t1 = threading.Thread(target=add) t2 = threading.Thread(target=add) t1.start() t2.start() t1.join() t2.join() print(count) # 200000
    第 31 题代码实战
    生成器(必做)
    用生成器推导式创建生成器,并用 for 遍历打印。
    再写一个含 yield 的生成器函数,用 next 至少取两次,说明每次从何处继续执行(注释)。
    查看参考答案 ▼
    g = (x * 2 for x in range(4)) for v in g: print(v) def gen(n): for i in range(n): yield i it = gen(3) print(next(it)) # 0 print(next(it)) # 1
    第 32 题代码实战
    asyncio 入门与并发任务(重点必做)
    定义 async def work(name): 内 print 开始,await asyncio.sleep(1),print 结束。
    定义 async def main(),用 create_task 同时调度至少两个 work,再 await 等待。
    最外层用 asyncio.run(main())。注释说明并发 vs 串行的耗时区别。
    查看参考答案 ▼
    import asyncio async def work(name): print("start", name) await asyncio.sleep(1) print("end", name) async def main(): t1 = asyncio.create_task(work("A")) t2 = asyncio.create_task(work("B")) await t1 await t2 asyncio.run(main())
    第 33 题代码实战
    CPU 密集型 vs I/O 密集型(选做)
    用一段话对比:CPU 密集型任务在 CPython 下更适合多进程还是多线程?I/O 密集型更适合线程还是协程?简要说明理由。
    查看参考答案 ▼
    CPU 密集型:在 CPython 下多线程受 GIL 影响,纯 Python 计算往往难以吃满多核,更适合用多进程将任务分配到多核。I/O 密集型:线程可在 I/O 阻塞时让出 CPU;协程在单线程事件循环里通过 await 挂起等待,大量 I/O 并发时开销更小,适合高并发网络/等待场景。
    第 34 题代码实战
    join() vs 互斥锁(选做)
    查阅或回忆:join() 等待子线程结束与用互斥锁保护临界区,在"牺牲并行度"方面有何异同(各写一两句)。
    查看参考答案 ▼
    join():让调用方等待某个线程先跑完,其他线程期间是否并行取决于你 join 的方式,容易写成阶段性串行。互斥锁:只保证临界区串行,锁外其他线程仍可并行,并行度通常好于整条线程顺序 join 的写法,但锁粒度过大也会接近单线程。