解析验证Java与Python多线程实现:用户级还是内核级

设计一个实验,验证Java或者Python(做一个或者两个都做)的多线程是用户级多线程还是内核级多线程。写明实验的设计思路、代码、测试结果(附截图)和结论

知识梳理:

  1. 用户级线程:用户级线程是在用户空间管理的线程,线程的调度和管理完全由用户程序来控制,而不是由操作系统内核进行调度。由于用户级线程不被操作系统直接调度,当一个线程在执行时,整个进程会被认为是占用 CPU,因此其他用户级线程无法同时运行,尤其是在 CPU 密集型任务中,这限制了并行性。
  2. 内核级线程:由操作系统内核管理。每个线程都被内核识别,可以进行独立的调度多个内核级线程可以在多核处理器上并行执行,适合 CPU 密集型任务。

解:

Java

  1. 设计思路:

通过观察线程的调度和执行情况,判断 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. 结论:

  1. 所有线程的执行时间相对接近,并且执行的时间和系统线程调度的行为一致,说明 Java 的多线程实现是内核级多线程,因为内核能够直接控制线程的调度
  2. 可以看到随着程序运行对应的线程数100,任务管理器中的线程数也随着增加对应的线程数量.

Python

  1. 设计思路:

通过观察线程的调度和执行情况,判断 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_

物联沃分享整理
物联沃-IOTWORD物联网 » 解析验证Java与Python多线程实现:用户级还是内核级

发表回复