This is a creation in Article, where the information may have evolved or changed.
The previous blog is mainly about how to avoid using too many system threads or processes in high concurrency, but if the number of threads is reduced, the CPU utilization itself is not up, then the capacity of the system is very low, so it is still not able to achieve high concurrency.
In general, we will set the number of threads equal to the number of CPUs, the full use of the CPU is equivalent to how to keep the thread working, to avoid wasting time waiting for system calls to return, thereby increasing the system capacity.
Many of the asynchronous frameworks under the Linux platform are designed based on Epoll, but the epoll itself only supports FD, which means that the file IO and socket are well supported, but not for other system calls, which can still cause congestion at the time of invocation, such as creat, unlink, and so on. In most cases, the ability to asynchronously process file IO and sockets has met our needs, such as Libevent, which is supported only by the Java NIO.
node. JS supports more, specifically referring to his FS module, which provides both synchronous and asynchronous invocation interfaces for a large number of system calls.
The go language does not require the developer to do special handling of the system calls when programming, and I believe he has done some internal processing to support his high concurrency, but after all, seeing is believing.
The go language and system call module is placed in the Syscall package, and the above encapsulates the "OS", "Time", "net" and other modules, and recommends the use of the following modules, single from the interface of syscall inside the function, see no asynchronous non-blocking signs, Can only be analyzed from the source code perspective.
The source code for the Syscall package is located in files such as Src/pkg/syscall/syscall_linux.go, but the functions inside are simply a wrapper over the lower function, such as
// sys Open (path string, mode int, perm uint32) (fd int, errno int)
string int int int) {
return Open (path, mode| O_largefile, Perm)
}
The code that is actually asynchronously is located in a file such as Src/pkg/syscall/zsyscall_linux_amd64.go, which is compiled from the above file, in the following example
string int int int) {
R0, _, E1: = Syscall (Sys_open, uintptr (unsafe. Pointer (stringbyteptr (path)), UIntPtr (mode), UIntPtr (Perm))
int (R0)
int (E1)
Return
}
The definition of Syscall is located in Src/pkg/syscall/asm_linux_amd64.s, which is written in the assembly, but I do not understand the assembly (tears)
TextSyscall(SB),7,$0
PagerRuntime Entersyscall (SB)
Movq -(SP), DI
Movq -(SP), SI
Movq +(SP), DX
MOVQ $0, R10
MOVQ $0, R8
MOVQ $0, R9
Movq8(SP), AX//SyscallEntry
SYSCALL
CMPQ AX, $0xfffffffffffff001
JLS OK
Movq $-1, +(SP)//R1
MOVQ $0, -(SP)//R2
Negq AX
Movq AX, About(SP)//errno
PagerRuntime Exitsyscall (SB)
RET
OK:
Movq AX, +(SP)//R1
Movq DX, -(SP)//R2
MOVQ $0, About(SP)//errno
PagerRuntime Exitsyscall (SB)
RET
where runtime Entersyscall and runtime Exitsyscall are located in SRC/PKG/RUNTIME/PROC.C
Analysis is not going on, but it can be confirmed that the go language does what, to avoid the system calls blocked threads, to ensure that the program can fully use the CPU.