精华内容
下载资源
问答
  • 线程绑核
    千次阅读
    2019-10-26 10:04:28

    如果你在开发低延迟的 Netty 应用程序,那么你可能了解过线程亲和性(thread affinity)这一概念。线程亲和性是指一个线程可以被强制在某一特定的 CPU 核和 CPU 核组上运行。这样你就可以在操作系统调度过程中消除线程迁移,提升性能。幸运的是,目前就有一个名为 Java-Thread-Affinity 的 Java 库,可以轻松地与 Netty 应用集成。

    首先,需要添加下面的依赖到 Maven pom.xml 里:

    <dependency>
        <groupId>net.openhft</groupId>
        <artifactId>affinity</artifactId>
        <version>3.0.6</version>
    </dependency>
    

    然后,创建一个 AffinityThreadFactory,并将其传递给 EventLoopGroup

    final int acceptorThreads = 1;
    final int workerThreads = 10;
    EventLoopGroup acceptorGroup = new NioEventLoopGroup(acceptorThreads);
    ThreadFactory threadFactory = new AffinityThreadFactory("atf_wrk", AffinityStrategies.DIFFERENT_CORE);
    EventLoopGroup workerGroup = new NioEventLoopGroup(workerThreads, threadFactory);
    
    ServerBootstrap serverBootstrap = new ServerBootstrap().group(acceptorGroup, workerGroup);
    

    注意:要把应用使用的 CPU 从系统调度器里隔离出来,才能做到尽量低的延迟。但是,这将导致系统调度器无法在这些 CPU 上运行别的用户线程。隔离方法是修改内核启动参数,在 grub.conf 文件里添加 isolcpus= 。

    更多相关内容
  • cpu一般有多个物理核心,但在运行进程和线程时候,可以将其绑定或者指定到某一个或者多个核心上运行。我们在系统上有两种方法可以查看cpu核心数。 1.cat /proc/cpuinfo查看cpu的核心数以及信息,这里以树莓派3B为例...

    查看cpu核心数

    cpu一般有多个物理核心,但在运行进程和线程时候,可以将其绑定或者指定到某一个或者多个核心上运行。我们在系统上有两种方法可以查看cpu核心数。

    1.cat /proc/cpuinfo查看cpu的核心数以及信息,这里以树莓派3B为例:

    processor       : 0
    model name      : ARMv7 Processor rev 4 (v7l)
    BogoMIPS        : 38.40
    Features        : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstrm crc32
    CPU implementer : 0x41
    CPU architecture: 7
    CPU variant     : 0x0
    CPU part        : 0xd03
    CPU revision    : 4

    processor       : 1
    model name      : ARMv7 Processor rev 4 (v7l)
    BogoMIPS        : 38.40
    Features        : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstrm crc32
    CPU implementer : 0x41
    CPU architecture: 7
    CPU variant     : 0x0
    CPU part        : 0xd03
    CPU revision    : 4

    processor       : 2
    model name      : ARMv7 Processor rev 4 (v7l)
    BogoMIPS        : 38.40
    Features        : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstrm crc32
    CPU implementer : 0x41
    CPU architecture: 7
    CPU variant     : 0x0
    CPU part        : 0xd03
    CPU revision    : 4

    processor       : 3
    model name      : ARMv7 Processor rev 4 (v7l)
    BogoMIPS        : 38.40
    Features        : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstrm crc32
    CPU implementer : 0x41
    CPU architecture: 7
    CPU variant     : 0x0
    CPU part        : 0xd03
    CPU revision    : 4

    Hardware        : BCM2835
    Revision        : a22082
    Serial          : 000000005a77a4ec

    2.使用C代码:

    #include <unistd.h>
    #include <stdio.h>
    #include <sys/sysinfo.h>
    
    int main (void)
    {
            printf("cpu core cnt:%d\n",sysconf(_SC_NPROCESSORS_ONLN));
            printf("cpu core cnt:%d\n",get_nprocs());
    }
    

    pi@raspberrypi:~/test $ gcc test.c -o test
    pi@raspberrypi:~/test $ ./test
    cpu core cnt:4
    cpu core cnt:4

    可以看到树莓派3B一共有4个物理核心。

    如何将进程绑定核心运行呢?

    1.可以使用tasklet命令,举例如下:

    #include <stdio.h>
    
    
    int main(void)
    {
            while(1);
    }
    

    pi@raspberrypi:~/test $ gcc loop.c -o loop
    pi@raspberrypi:~/test $ ./loop &
    [2] 3148
    pi@raspberrypi:~/test $ taskset -p 3148
    pid 3148's current affinity mask: f

    编译后放后台运行,使用tasklet查pid我们可以看到mask是f,也就是二进制的1111,表明这个进程可以在4个核心上被调度。当然我们也可以使用tasklet -c来指定程序在哪些核心上运行

    pi@raspberrypi:~/test $ taskset -c 0 ./loop &
    [2] 3183
    pi@raspberrypi:~/test $ taskset -p 3183
    pid 3183's current affinity mask: 1

    可以看到,程序只能在核心0上运行

    2.使用C代码:

    关键函数:

    int sched_setaffinity(pid_t pid, size_t cpusetsize, cpu_set_t *mask);
    
    int sched_getaffinity(pid_t pid, size_t cpusetsize, cpu_set_t *mask);
    #include <stdio.h>
    #define __USE_GNU
    #include <sched.h>
    #include <pthread.h>
    
    int main(void)
    {
            cpu_set_t cpuset;
            CPU_ZERO(&cpuset);
            CPU_SET(0,&cpuset);
            sched_setaffinity(0, sizeof(cpu_set_t), &cpuset);
            while(1);
    }
    

    pi@raspberrypi:~/test $ gcc loop.c -o loop -lpthread
    pi@raspberrypi:~/tes./loop  &
    [4] 3389
    pi@raspberrypi:~/test $ taskset -p 3389
    pid 3389's current affinity mask: 1

    编译后运行,可以看到,程序只能在核心0上运行
     

    如何将线程绑定核心运行呢?

    使用C代码:

    关键函数:

    int pthread_setaffinity_np(pthread_t thread, size_t cpusetsize, const cpu_set_t *cpuset);
    int pthread_getaffinity_np(pthread_t thread, size_t cpusetsize, cpu_set_t *cpuset);

    写了一个简单的示例,先不设置线程亲和性,只回读状态:

    #include <stdio.h>
    #include <stdlib.h>
    #define __USE_GNU
    #include <sched.h>
    #include <pthread.h>
    
    
    void thread1(void)
    {
            printf("this is thread1\n");
            while(1);
    
    }
    
    void thread2(void)
    {
            printf("this is thread2\n");
            while(1);
    
    }
    int main(void)
    {
            pthread_t id1,id2;
            int ret;
            cpu_set_t cpuset;
    
            ret = pthread_create(&id1,NULL,(void *)thread1,NULL);
            if(ret != 0)
            {
                    printf("create thread err!\n");
                    exit(1);
            }
    
            ret = pthread_create(&id2,NULL,(void *)thread2,NULL);
            if(ret != 0)
            {
                    printf("create thread err!\n");
                    exit(1);
            }
            pthread_getaffinity_np(id1, sizeof(cpu_set_t),&cpuset);
            printf("thread1 affinity:%x\n",cpuset);
            pthread_getaffinity_np(id2, sizeof(cpu_set_t),&cpuset);
            printf("thread2 affinity:%x\n",cpuset);
            while(1);
    }
    

    pi@raspberrypi:~/test $ gcc pthread.c -o pthread -lpthread
    pi@raspberrypi:~/test $ ./pthread &
    [3] 3689
    pi@raspberrypi:~/test $

    thread1 affinity:f
    thread2 affinity:f
    this is thread2
    this is thread1
     

    编译并执行程序后,可以看到线程1和线程2的亲和性都是f,可以在4个核心上运行。我们通过pstree也可以看到这个程序创建了两个线程。

            ├─sshd─┬─sshd───sshd───bash─┬─pstree
            │      │                    ├─pthread
            │      │                    └─2*[pthread───2*[{pthread}]]
     

    接下来我们把亲和性设置加上,代码如下:

    #include <stdio.h>
    #include <stdlib.h>
    #define __USE_GNU
    #include <sched.h>
    #include <pthread.h>
    
    
    void thread1(void)
    {
            printf("this is thread1\n");
            while(1);
    
    }
    
    void thread2(void)
    {
            printf("this is thread2\n");
            while(1);
    
    }
    int main(void)
    {
            pthread_t id1,id2;
            int ret;
            cpu_set_t cpuset;
    
            ret = pthread_create(&id1,NULL,(void *)thread1,NULL);
            if(ret != 0)
            {
                    printf("create thread err!\n");
                    exit(1);
            }
    
            ret = pthread_create(&id2,NULL,(void *)thread2,NULL);
            if(ret != 0)
            {
                    printf("create thread err!\n");
                    exit(1);
            }
            CPU_ZERO(&cpuset);
            CPU_SET(0,&cpuset);
            pthread_setaffinity_np(id1,sizeof(cpu_set_t), &cpuset);
            CPU_ZERO(&cpuset);
            CPU_SET(1,&cpuset);
            pthread_setaffinity_np(id2,sizeof(cpu_set_t), &cpuset);
    
    
    
            pthread_getaffinity_np(id1, sizeof(cpu_set_t),&cpuset);
            printf("thread1 affinity:%x\n",cpuset);
            pthread_getaffinity_np(id2, sizeof(cpu_set_t),&cpuset);
            printf("thread2 affinity:%x\n",cpuset);
            while(1);
    }
    

    pi@raspberrypi:~/test $ gcc pthread.c -o pthread -lpthread
    pi@raspberrypi:~/test $ ./pthread &
    [6] 3794
    pi@raspberrypi:~/test $

    thread1 affinity:1
    thread2 affinity:2
    this is thread2
    this is thread1

    编译运行后可以看到,线程1只能在核心0上运行,线程2只能在核心1上运行。

    欢迎批评指正
     

    展开全文
  • 1、多核NUMA结构 NUMA(Non-uniform memory access,非统一内存访问架构)出现前,CPU通过内存控制器访问内存,...2、NUMA绑核优化思路 避免线程在运行中在不同核上漂移,从而引起访问NUMA远端内存。openGauss通过配

    1、多核NUMA结构

    NUMA(Non-uniform memory access,非统一内存访问架构)出现前,CPU通过内存控制器访问内存,随着CPU核的增加,内存控制器成为评价。内存控制器一般拆分内存平均分配到各个node节点上,CPU访问本地内存速度快,跨片访问慢。NUMA距离定义为:NUMA node的处理器和内存块的物理距离。通过numactl工具可以查看到CPU访问的距离信息。

    2、NUMA绑核优化思路

    避免线程在运行中在不同核上漂移,从而引起访问NUMA远端内存。openGauss通过配置参数thread_pool_attr控制CPU绑核分配,该参数仅在enable_thread_pool打开后生效。参数分为3部分:’thread_num,group_num,cpubind_info’。

    其中thread_num:线程池中线程总数,取值0-4096。0表示根据CPU核数量自动配置线程池中线程数。如果大于0,线程池中线程数等于该值

    group_num:线程池中线程分组个数。0-64。0表示根据NUMA组个数自动配置线程池中分组个数,否正为group_num个数。

    cpubind_info:线程池是否绑核的配置参数。可以配置:

    1(nobind),线程不绑核

    2(allbind),利用当前系统所有能查询到的CPU核做线程绑核;

    3 (nodebind:1,2),利用NUMA组1,2中CPU核进行绑核;

    4 (cpubind:0-30),利用0-30号CPU核进行绑核。

    默认值‘16,2,(nobind)’

    为充分利用CPU,线程数略大于核数。因为可能由线程等待,此时切换大其他线程进行。

    3、源码解析

    操作流程

    • 在PostmasterMain中开始设置线程绑定动作
    • 如果设置enable_thread_pool,才会调用SetThreadPoolInfo函数

      1. 首先InitCpuInfo将CPU信息结构m_cpuInfo初始化
      2. 判定是否已有CPU进行了绑定GetInstanceBind
      3. GetCpuAndNumaNum计算CPU个数及NUMA节点个数
      4. ParseAttr函数解析thread_pool_attr字符串
      5. GetSysCpuInfo函数获取CPU信息
      6. SetGroupAndTreadNum设定组个数及每个组中线程数
    • 在ServerLoop函数中接收用户端连接,并进行CPU绑定

      • 由函数g_threadPoolControler->Init完成
      • 完成线程创建及CPU绑定的函数是TreadPoolGroup::Init完成

    GetCpuAndNumaNum

    通过lscpu命令来计算CPU核、NUMA个数。

    void ThreadPoolControler::GetCpuAndNumaNum()
    {
        char buf[BUFSIZE];
        FILE* fp = NULL;
        if ((fp = popen("lscpu", "r")) != NULL) {
            while (fgets(buf, sizeof(buf), fp) != NULL) {
                if (strncmp("CPU(s)", buf, strlen("CPU(s)")) == 0 &&
                   strncmp("On-line CPU(s) list", buf, strlen("On-line CPU(s) list")) != 0 &&
                    strncmp("NUMA node", buf, strlen("NUMA node")) != 0) {
                    char* loc = strchr(buf, ':');
                    m_cpuInfo.totalCpuNum = pg_strtoint32(loc + 1);
                } else if (strncmp("NUMA node(s)", buf, strlen("NUMA node(s)")) == 0) {
                    char* loc = strchr(buf, ':');
                    m_cpuInfo.totalNumaNum = pg_strtoint32(loc + 1);
                }
            }
            pclose(fp);
        } 
    

    GetSysCpuInfo

    • 通过fp = popen(“lscpu -b -e=cpu,node”, “r”);执行lscpu命令获取cpuid和numaid
    • 通过CPU_ISSET判断CPU是否绑定,最后计算出活跃未绑定的CPU个数m_cpuInfo.activeNumaNum

    SetGroupAndThreadNum

    • 进行线程绑定,默认情况下线程组个数2,每组里面线程个数16
    • ConstrainThreadNum限定线程池大小m_maxPoolSize为min(4096,max_connection,),线程个数m_threadNum = Min(m_threadNum, m_maxPoolSize);

    ThreadPoolGroup::Init

    m_listener->StartUp();//开启一个新线程
    InitWorkerSentry();
    |-- AddWorker
        |-- AttachThreadToNodeLevel:: pthread_setaffinity_np
    CPU_SET(m_groupCpuArr[i], &m_nodeCpuSet);//循环将CPU加入CPU集合
    

    NUMA优化相关函数

    openGauss中所有numa相关函数都可以通过宏定义ifdef __USE_NUMA找到其定义及调用的地方。

    int numa_available(void):NUMA的API是否可以在平台上正常使用
    int numa_max_node(void):当前系统上最大NUMA节点号
    void * numa_alloc_onnode(size_t size,int node):在一个指定NUMA节点分配内存
    void numa_free(void *start,size_t size):释放起始地址指定的内存
    int numa_run_on_node(int node):运行当前任务在指定NUMA节点上
    void numa_set_localalloc(void):设置当前的任务内存分配策略为本地化分配
    void numa_set_preferred(int node):为当前任务设置偏好NUMA节点
    void numa_set_interleave_mask(struct bitmask*nodemask):在一系列numa节点上分配交叉内存
    int pthread_getaffinity_np(pthread_t thread,size_t cpusetsize,cpu_set_t *cpuset):设置线程在某个CPU上运行。
    
    1. sched_getaffinity和pthread_getaffinity_np都是绑核的函数。
    2. numa_set_preferred设置当前线程优先分配内的结点。内存分配器先尝试从这个结点上分配内存。如果这个结点没有足够的空间,它会尝试其他结点。
    3. numa_set_interleave_mask函数可以让当前线程以交错(interleaving)方式分配内存。未来所有的内存,将会从掩码给定的结点上轮询(round robing)分配。numa_all_nodes将内存分配交错(interleaving)在所有的node上。numa_no_nodes将会关闭交错分配内存。numa_get_interleave_mask函数返回当前的交错掩码。这可以将当前的内存分配策略保存到文件中,在策略修改后,再次恢复。
    展开全文
  • #include <... //sched_setaffinity 绑核 #define _GNU_SOURCE #include <sys/prctl.h> //起名用 void test_thread() { int cpus = sysconf(_SC_NPROCESSORS_CONF); //总共多少个CPU核 cons
    #include <thread> //线程
    
    #include <unistd.h> // sysconf 
    #include <sched.h> //sched_setaffinity 绑核
    #define _GNU_SOURCE 
    
    #include <sys/prctl.h> //起名用
    
    
    void test_thread()
    {
    	int cpus = sysconf(_SC_NPROCESSORS_CONF); //总共多少个CPU核
    	const char *newThreadNamePtr = "stage1"; //线程起名
    	prctl(PR_SET_NAME, newThreadNamePtr);
    	cpu_set_t mask;
    	CPU_ZERO(&mask);
    	CPU_SET(4, &mask);
    	
    	/*设置cpu 亲和性(affinity)*/
    	sched_setaffinity(0, sizeof(mask), &mask); //0表示当前线程
    }
    
    int main()
    {
    	std::thread t1(test_thread);
    	t1.join();
    	return 0;
    }
    
    
    展开全文
  • 线程绑核的简单操作

    千次阅读 2017-08-10 09:31:03
    为了加快程序的运行速度和充分利用CPU资源,我们可以人为将不同线程绑定在不同的cup上,例如有两个线程A,B,其中A已经在CPU0上运行,并且CPU0上还有其他的任务,那么我们可以将线程B到CPU1上,这样就可以减轻CPU0...
  • Java-Thread-Affinity,将Java线程绑定到给定的内核.zip
  • Linux系统提供API函数sched_setaffinity和sched_getaffinity用于设置或获取线程的可以使用的CPU。int sched_setaffinity(pid_t pid, unsigned int cpusetsize, cpu_set_t*mask);这个函数中pid表示需要设置或获取...
  • 线程绑定CPU详解

    千次阅读 2021-03-04 19:55:19
    在多线程编程中,每个线程处理的任务优先级是不一样的,对于要求实时性比较高的线程或者是主线程,对于这种线程我们可以在创建线程时指定其绑定到某个CPU上,以后这个就专门处理该线程。这样可以使得该线程的...
  • 一、概述 现在大家使用的基本上都是多核cpu。平时应用程序在运行时都是由操作系统管理的。操作系统对应用进程进行调度,...把某个进程/线程绑定到特定的cpu上后,该进程就会一直在此上运行,不会再被操作系统调...
  • 可以配置: 1(nobind),线程不绑核 2(allbind),利用当前系统所有能查询到的CPU核做线程绑核; 3 (nodebind:1,2),利用NUMA组1,2中CPU核进行绑核; 4 (cpubind:0-30),利用0-30号CPU核进行绑核。 默认值‘16...
  • 如果需要开发低延迟的网络应用,那应该对线程亲和性(Thread affinity)有所了解。线程亲和性能够强制使你的应用线程运行在特定的一个或多个cpu上。通过这种方式,可以消除操作系统进行调度造成的线程的频繁的上下文...
  • 如何将进程、线程与CPU进行绑定 CPU绑定指的是在多核CPU的系统中将进程或线程绑定到指定的CPU上去执行。在Linux中,我们可以利用CPU affinity属性把进程绑定到一个或多个CPU上。 CPU Affinity是进程的一个属性...
  • 线程与cpu核心绑定: SetProcessAffinityMask(GetCurrentProcess(),1); //线程绑定cpu核心 使用上面代码,可将当前的线程与cpu的某个核心绑定。 其中第二个参数为使用的cpu核心位置,其中cpu的核心数读取可参考...
  • 线程/进程和绑定(CPU亲和性)

    千次阅读 2021-03-01 15:04:13
    文章目录前言一、CPU亲和性1 前言2 为何要手动绑定线程/进程到CPU3 多进程和多线程在多核CPU上运行:4 应用场景举例二、Linux的CPU亲和性特征1 软亲和性2 硬亲和性3 硬亲和性使用场景三、查看CPU的1 使用指令2 ...
  • $ 总逻辑CPU数 = 物理CPU个数 X 每颗物理CPU的核数 X 超线程数 $ 查看物理CPU个数 cat /proc/cpuinfo| grep "physical id"| sort| uniq| wc -l $ 查看每个物理CPU中core的个数(即核数) cat /proc/cpuinfo| grep ...
  • OpenMP的三种线程绑定方式

    千次阅读 2020-08-12 06:34:51
    之前看到OpenMP入门教程比较多,但是绑定这部分比较少。把绑定的语句先写在这里。 /*omp的三种绑定方式*/ #pragma omp parallel proc_bind(master) #pragma omp parallel proc_bind(close) #pragma omp ...
  • 方法一: 方法一:ps -eLF 查找 PSR 字段值 [test1280@localhost 20190227]$ ps -eLF UID PID PPID LWP C NLWP SZ RSS PSR STIME TTY TIME CMD root 1 0 1 0 1 4836 1548 2 ...-p:查看的进程id -a: 查看进程的所有线程
  • 线程绑定CPU

    千次阅读 2016-06-27 08:57:20
    Linux系统提供API函数sched_setaffinity和sched_getaffinity用于设置或获取线程的可以使用的CPU。 int sched_setaffinity(pid_t pid, unsigned int cpusetsize, cpu_set_t *mask); 这个函数中pid表示需要...
  • linux下把进程/线程绑定到特定cpu上运行

    万次阅读 多人点赞 2018-07-08 12:20:05
    概述 现在大家使用的基本上都是多核cpu,一般是4的。平时应用程序在运行时都是由操作系统管理的。操作系统对应用进程进行调度,使其在...把某个进程/线程绑定到特定的cpu上后,该进程就会一直在此上运行,不...
  • Android 高通骁龙CPU线程与CPU的绑定

    千次阅读 2022-04-20 21:58:49
    进程、线程绑定cpu的问题,在这里将所学记录一下。高通骁龙采用1+3+4的超独特设计,Prime超大、3个Kryo Gold核心和4个Kryo Silver核心。 其中0-3是Silver核芯,4-6是Gold核心,7是Prime超大。 绑定核心的...
  • gcc test.c -lpthread -D_GNU_SOURCE 验证方式: 运行程序,使用命令top查看指定的进程的PID: 然后使用命令: top -H -p PID 按f键,并使用上下切换,利用空格键选中nTH,P: 按esc键,P所在的列就是线程运行的CPU号...
  • 目的 某个进程需要较高的运行效率时,就有必要考虑将其绑定到单独...查看进程pid现在的绑核情况 taskset -p pid pid 2726's current affinity mask: 6 显示的十进制数字6--->转换为2进制是110,每个1对应一个cp
  • 物理CPU个数 * CPU内核数 开启了超线程逻辑CPU个数 = 物理CPU个数 * CPU内核数 没有开启超线程CPU数,物理,逻辑的查看方法:#cat /proc/cpuinfoprocessor : 0vendor_id :GenuineIntelcpu family :6model...
  • 概述 现在大家使用的基本上都是多核cpu,一般是4的。平时应用程序在运行时都是由操作系统管理的。操作系统对应用进程进行调度,使其在...把某个进程/线程绑定到特定的cpu上后,该进程就会一直在此上运行,不...
  • 线程或进程绑定到特定的cpu

    千次阅读 2021-05-24 10:44:03
    返回系统可以使用的核数,但是其值会包含系统中禁用的的数目,因此该值并不代表当前系统中可用的核数 2) 当前系统可以使用的核数 int sysconf(_SC_NPROCESSORS_ONLN); 真正代表了系统当前可用的核数 与以上两个...
  • 所谓绑核,其实就是设定某个进程/线程与某个CPU核的亲和力(affinity)。设定以后,Linux调度器就会让这个进程/线程只在所绑定的核上面去运行。但并不是说该进程/线程就独占这个CPU的核,其他的进程/线程还是可以在...
  • C++多线程,为线程绑定cpu

    千次阅读 2019-06-25 18:40:12
    /* 查看当前线程所运行的所有cpu*/ for ( i = 0 ; i < cpus ; i ++ ) { if ( CPU_ISSET ( i , & get ) ) { LOG ( WARNING ) thread_name " : " ( int ) pthread_self ( ) ...
  • 目录引言:一、什么是绑核二、如何绑核2.1 掩码形式绑核2.2 列表形式 三、taskset的用法3.1 taskset常用参数3.2 下载...所谓绑核,其实就是设定某个进程/线程与某个CPU核的亲和力(affinity)。设定以后,Linux调度器

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 117,547
精华内容 47,018
关键字:

线程绑核