CPU affinity 进程和线程的亲缘性
设置Processor Affinity 作用:
- 1.进程和线程的亲缘性(affinity),使进程或线程在指定的CPU(核)上运行.(比如程序A,在第4个核心上运行)
- 2.设置进程 或者 线程, 使用CPU的数量(比如程序A,在第1,2,3个(共3个核心)核心上运行)
- 3.CPU负载均衡
Specific operating systems
On Linux, the CPU affinity of a process can be altered with the taskset(1)
program[2] and the sched_setaffinity(2)
system call. The affinity of a thread can be altered with one of the library functions: pthread_setaffinity_np(3)
or pthread_attr_setaffinity_np(3)
.
On Windows NT and its successors, thread and process CPU affinities can be set separately by using SetThreadAffinityMask[7] and SetProcessAffinityMask[8] API calls or via the Task Manager interface (for process affinity only).
"White Paper - Processor Affinity" - From tmurgent.com. Accessed 2007-07-06.
详细看wiki
一些帖子
假设业务模型中耗费cpu的分四种类型,(1)网卡中断(2)1个处理网络收发包进程(3)耗费cpu的n个worker进程(4)其他不太耗费cpu的进程
基于1中的 负载均衡是针对进程数,那么(1)(2)大部分时间会出现在cpu0上,(3)的n个进程会随着调度,平均到其他多个cpu上,(4)里的进程也是随着调度分配到各个cpu上;
当发生网卡中断的时候,cpu被打断了,处理网卡中断,那么分配到cpu0上的worker进程肯定是运行不了的
其他cpu上不是太耗费cpu的进程获得cpu时,就算它的时间片很短,它也是要执行的,那么这个时候,你的worker进程还是被影响到了;按照调度逻辑,一种非常恶劣的情况是:(1)(2)(3)的进程全部分配到cpu0上,其他不太耗费cpu的进程数很多,全部分配到cpu1,cpu2,cpu3上。。那么网卡中断发生的时候,你的业务进程就得不到cpu了
如果从业务的角度来说,worker进程运行越多,肯定业务处理越快,人为的将它捆绑到其他负载低的cpu上,肯定能提高worker进程使用cpu的时间
每个cpu都利用起来了,负载会比不绑定的情况下好很多
有效果的原因:
依据《linux内核设计与实现》的42节,人为控制一下cpu的绑定还是有用处地
linux的SMP负载均衡是基于进程数的,每个cpu都有一个可执行进程队列(为什么不是线程队列呢??),只有当其中一个cpu的可执行队列里进程数比其他cpu队列进程数多25%时,才会将进程移动到另外空闲cpu上,也就是说cpu0上的进程数应该是比其他cpu上多,但是会在25%以内。
windows
SetProcessAffinityMask
GetProcessAffinityMask
SetThreadAffinityMask
SetThreadIdealProcessor
.....
SetThreadAffinityMask - MSDN Library
SetProcessAffinityMask - MSDN Library
linux
"taskset" at LinuxCommand.org. Accessed 2007-07-06.
pthread_getaffinity_np(3)
pthread_setaffinity_np(3)
pthread_attr_getaffinity_np(3)
pthread_attr_setaffinity_np(3)
BSD
cpuset(1) - FreeBSD manpage
"RN affinity API". Developer.apple.com
golang多平台
使用go的routines和channel,可以充分利用多核处理器,提高高CPU资源占用计算的速度。如下列计算π的值
package main
import (
"fmt"
"runtime"
"time"
)
var n int64 = 10000000000
var h float64 = 1.0 / float64(n)
func f(a float64) float64 {
return 4.0 / (1.0 + a*a)
}
func chunk(start, end int64, c chan float64) {
var sum float64 = 0.0
for i := start; i < end; i++ {
x := h * (float64(i) + 0.5)
sum += f(x)
}
c <- sum * h
}
func main() {
//记录开始时间
start := time.Now()
var pi float64
np := runtime.NumCPU()
runtime.GOMAXPROCS(np)
c := make(chan float64, np)
for i := 0; i < np; i++ {
go chunk(int64(i)*n/int64(np), (int64(i)+1)*n/int64(np), c)
}
for i := 0; i < np; i++ {
pi += <-c
}
fmt.Println("Pi: ", pi)
//记录结束时间
end := time.Now()
//输出执行时间,单位为毫秒。
fmt.Printf("spend time: %vs\n", end.Sub(start).Seconds())
}