解析验证Java与Python多线程实现:用户级还是内核级
设计一个实验,验证Java或者Python(做一个或者两个都做)的多线程是用户级多线程还是内核级多线程。写明实验的设计思路、代码、测试结果(附截图)和结论
知识梳理:
|
解:
Java:
通过观察线程的调度和执行情况,判断 Java 中的多线程是用户级还是内核级。如果所有线程的执行时间相对接近,并且执行的时间和系统线程调度的行为一致,说明 Java 的多线程实现是内核级多线程,因为内核能够直接控制线程的调度。并且通过任务管理器查看系统线程数量是否随着程序中启动多个线程而对应随之增加。
2. 代码: package com.example;
public class Main { private static final int NUM_THREADS = 100; private static final int NUM_ITERATIONS = 100000;
public static void main(String[] args) { Thread[] threads = new Thread[NUM_THREADS];
for (int i = 0; i < NUM_THREADS; i++) { threads[i] = new Thread(new Task(i)); threads[i].start(); }
for (int i = 0; i < NUM_THREADS; i++) { try { threads[i].join(); } catch (InterruptedException e) { e.printStackTrace(); } }
System.out.println("所有的线程执行完毕."); }
static class Task implements Runnable { private final int threadId;
public Task(int threadId) { this.threadId = threadId; }
@Override public void run() { long startTime = System.currentTimeMillis();
// 模拟计算 for (int i = 0; i < NUM_ITERATIONS; i++) { Math.sin(i); Thread.yield(); }
long endTime = System.currentTimeMillis(); System.out.println("线程" + threadId + " 在 " + (endTime – startTime) + " ms."+ "完成"); } } }
3. 测试结果:
4. 结论:
|
Python:
通过观察线程的调度和执行情况,判断 Python 中的多线程是用户级还是内核级。如果所有线程的执行时间相对接近,并且执行的时间和系统线程调度的行为一致,说明 Python 的多线程实现是内核级多线程,因为内核能够直接控制线程的调度。并且通过任务管理器查看系统线程数量是否随着程序中启动多个线程而对应随之增加。
2. 代码: import threading import time import math
# 定义计算任务 def compute_task(thread_id): start_time = time.time() for i in range(10000000): math.sin(i) end_time = time.time() print(f"线程 {thread_id} 在 {end_time – start_time:.2f} seconds 完成.")
# 主函数 def main(): threads = [] num_threads = 100 # 根据 CPU 核心数调整线程数量
for i in range(num_threads): thread = threading.Thread(target=compute_task, args=(i,)) threads.append(thread) thread.start()
for thread in threads: thread.join()
print("所有线程都完成.")
if __name__ == "__main__": main()
3. 测试结果:
由实验结果可知,由于 GIL 的限制,虽然可以创建多个线程,但它们无法同时在多个 CPU 核心上并行执行 Python 代码,这影响了实验判断python多线程是否用户级还是内核级的判断。
4. 重新校验:
import threading import os import ctypes # Windows API 获取当前线程 ID def get_tid(): return ctypes.windll.kernel32.GetCurrentThreadId() def worker(): print(f"进程 ID (PID): {os.getpid()}, Python 线程 ID: {threading.get_ident()}, 内核线程 ID (TID): {get_tid()}") if __name__ == "__main__": threads = [] for _ in range(10): t = threading.Thread(target=worker) t.start() threads.append(t) for t in threads: t.join() 5. 结论: 从结果可以看出,虽然在执行计算密集型任务时,Python 线程 看起来是串行执行的,这是 GIL(全局解释器锁) 造成的假象。然而在同一个进程中同时创建几个线程后,能够看到不同线程有其独属TID,证明了python多线程情况下是内核级线程,但是出于GIL的原因,在计算的时候并不能很好的利用并发的调度。 当然,GIL 只在执行 Python 代码时生效,但在 I/O 操作(如文件读写、网络请求、数据库访问)时,Python 会释放 GIL,允许其他线程执行。这意味着 Python 线程仍然能 并发处理 I/O 任务。 |
作者:NovakG_