-
-
Save tevino/3a4f4ec4ea9d0ca66d4f to your computer and use it in GitHub Desktop.
package main | |
import ( | |
"fmt" | |
"net" | |
"os" | |
"syscall" | |
) | |
const ( | |
EPOLLET = 1 << 31 | |
MaxEpollEvents = 32 | |
) | |
func echo(fd int) { | |
defer syscall.Close(fd) | |
var buf [32 * 1024]byte | |
for { | |
nbytes, e := syscall.Read(fd, buf[:]) | |
if nbytes > 0 { | |
fmt.Printf(">>> %s", buf) | |
syscall.Write(fd, buf[:nbytes]) | |
fmt.Printf("<<< %s", buf) | |
} | |
if e != nil { | |
break | |
} | |
} | |
} | |
func main() { | |
var event syscall.EpollEvent | |
var events [MaxEpollEvents]syscall.EpollEvent | |
fd, err := syscall.Socket(syscall.AF_INET, syscall.O_NONBLOCK|syscall.SOCK_STREAM, 0) | |
if err != nil { | |
fmt.Println(err) | |
os.Exit(1) | |
} | |
defer syscall.Close(fd) | |
if err = syscall.SetNonblock(fd, true); err != nil { | |
fmt.Println("setnonblock1: ", err) | |
os.Exit(1) | |
} | |
addr := syscall.SockaddrInet4{Port: 2000} | |
copy(addr.Addr[:], net.ParseIP("0.0.0.0").To4()) | |
syscall.Bind(fd, &addr) | |
syscall.Listen(fd, 10) | |
epfd, e := syscall.EpollCreate1(0) | |
if e != nil { | |
fmt.Println("epoll_create1: ", e) | |
os.Exit(1) | |
} | |
defer syscall.Close(epfd) | |
event.Events = syscall.EPOLLIN | |
event.Fd = int32(fd) | |
if e = syscall.EpollCtl(epfd, syscall.EPOLL_CTL_ADD, fd, &event); e != nil { | |
fmt.Println("epoll_ctl: ", e) | |
os.Exit(1) | |
} | |
for { | |
nevents, e := syscall.EpollWait(epfd, events[:], -1) | |
if e != nil { | |
fmt.Println("epoll_wait: ", e) | |
break | |
} | |
for ev := 0; ev < nevents; ev++ { | |
if int(events[ev].Fd) == fd { | |
connFd, _, err := syscall.Accept(fd) | |
if err != nil { | |
fmt.Println("accept: ", err) | |
continue | |
} | |
syscall.SetNonblock(fd, true) | |
event.Events = syscall.EPOLLIN | EPOLLET | |
event.Fd = int32(connFd) | |
if err := syscall.EpollCtl(epfd, syscall.EPOLL_CTL_ADD, connFd, &event); err != nil { | |
fmt.Print("epoll_ctl: ", connFd, err) | |
os.Exit(1) | |
} | |
} else { | |
go echo(int(events[ev].Fd)) | |
} | |
} | |
} | |
} |
If the compiler is a C compiler or a GO compiler what difference does it make? It is not the case that the binary produced by one is inherently "slower" than the other.
Yes, of course there's a huge difference.
GO compilers compiles your code to run inside a runtime, which is essentially an abstraction layer doing all the dirty work that C programmers manually do (memory management, process scheduling, and all of that).
But then again, this is the most important reason in my opinion:
epoll() is normally used because it provides a performance orders of magnitude bigger than a normal poll() or a select().
When you require very high performance, you don't want to ruin in because the garbage collector kicks in.
package syscall define the EPOLLET = -0x8000000 ,but epoll_event field "Events" need uint32 I'm confused 🤣
package syscall define the EPOLLET = -0x8000000 ,but epoll_event field "Events" need uint32 I'm confused 🤣
There's more than one way to skin a cat. Try something like: const EPOLLET uint32 = 1<<31
I guess the fd created for new connection needs to be removed from epollfd before go echo(int(events[ev].Fd)) , and then all data of the detached connection could be handled independently by a goroutine.
If the compiler is a C compiler or a GO compiler what difference does it make? It is not the case that the binary produced by one is inherently "slower" than the other.
Yes, of course there's a huge difference.
GO compilers compiles your code to run inside a runtime, which is essentially an abstraction layer doing all the dirty work that C programmers manually do (memory management, process scheduling, and all of that).But then again, this is the most important reason in my opinion:
epoll() is normally used because it provides a performance orders of magnitude bigger than a normal poll() or a select().
When you require very high performance, you don't want to ruin in because the garbage collector kicks in.
Or you want to do edge detection and sleep to save battery. in this case; you may be triggering code that itself doesn't need optimization and can run happily in a go with GC; but you want to sleep as much as possible until the triggering event.
If the compiler is a C compiler or a GO compiler what difference does it make? It is not the case that the binary produced by one is inherently "slower" than the other.
Yes, of course there's a huge difference.
GO compilers compiles your code to run inside a runtime, which is essentially an abstraction layer doing all the dirty work that C programmers manually do (memory management, process scheduling, and all of that).But then again, this is the most important reason in my opinion:
epoll() is normally used because it provides a performance orders of magnitude bigger than a normal poll() or a select().
When you require very high performance, you don't want to ruin in because the garbage collector kicks in.
Go is not Java. Go code does not get compiled into platform independent byte code which is then "interpreted" at runtime "inside" anything. Narrowly as it relates to epoll you are wrong in your assessment that cgo is faster at performing a syscall operation, it just isn't. More broadly as it relates to the runtime libraries used by different languages you are also wrong. For fun, you could look up how in C main() gets called by the c runtime library or in C++ you could investigate what happens when someone calls new or free..... In any event, the fact that a language and its runtime library has memory allocation and garbage collection functionality does not infer that it is by definition "slower" than a language that doesn't. Similarly, a language that doesn't, does not have determinism built-in to its memory allocation allocation/deallocation system, which is - believe it or not - a part of its runtime library functions. Lastly, you are not wrong that there are instances where you could write something in C/C++ that would perform better than the equivalent written in Go. But as it relates to using cgo for epoll in this case you are wrong to assume that syscall() used in cgo is by definition faster than syscall.Syscall in go.
If the compiler is a C compiler or a GO compiler what difference does it make? It is not the case that the binary produced by one is inherently "slower" than the other.