Go語言中實現基於 event loop 網路處理

2021-09-11 02:11:20 字數 2927 閱讀 3175

我們知道, go語言為併發程式設計提供了簡潔的程式設計方式, 你可以以"同步"的程式設計風格來併發執行**, 比如使用go關鍵字新開乙個goroutine。 對於網路程式設計,go標準庫和執行時內部採用epoll/kqueue/iocompletionport來實現基於event-loop的網路非同步處理,但是通過netpoll的方式對外提供同步的訪問。具體**可以參考 runtime/netpoll、net和internal/poll。

package poll supports non-blocking i/o on file descriptors with polling.

this supports i/o operations that block only a goroutine, not a thread.

this is used by the net and os packages.

it uses a poller built into the runtime, with support from the

runtime scheduler.

當然,我們平常不會設計到這些封裝的細節,正常使用net包就很方便的開發網路程式了, 但是,如果我們想自己實現基於epollevent-loop網路程式呢?

man epoll可以檢視epoll的相關介紹。下面這個例子來自tevino, 採用edge-triggered方式處理事件。

它採用syscall.socketsyscall.setnonblocksyscall.bindsyscall.listen系統呼叫來監聽埠,然後採用syscall.epollcreate1syscall.epollctlsyscall.epollwait來關聯這個監聽的file descriptor, 一旦有新的連線的事件過來,使用syscall.accept接收連線請求,並對這個連線file descriptor呼叫syscall.epollctl監聽資料事件。一旦連線有資料ready, 呼叫syscall.read讀資料,呼叫syscall.write寫資料。

來自

package main

import (

"fmt"

"net"

"os"

"syscall"

const (

epollet = 1 << 31

maxepollevents = 32

func echo(fd int)

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 else {

go echo(int(events[ev].fd))

上面的基於epoll只是乙個簡單的event-loop處理原型,而且在有些平台下(mac os)也不能執行,事件的處理也很粗糙,如果你想實現乙個完整的event-loop的網路程式, 可以參考下節的庫。

evio是乙個效能很高的event-loop網路庫,**簡單,功能強大。它直接使用epollkqueue系統呼叫,除了go標準net庫提供了另外一種思路, 類似libuv和libevent。

這個庫實現redis和haproxy等同的包處理機制,但並不想完全替代標準的net包。對於乙個需要長時間執行的請求(大於1毫秒), 比如資料庫訪問、身份驗證等,建議還是使用go net/http庫。

你可能知道, 由很多基於event-loop的程式, 比如nginx、haproxy、redis、memcached等,效能都非常不錯,而且它們都是單執行緒執行的,非常快。

這個庫還有乙個好處, 你可以在乙個event-loop中處理多個network binding。

乙個簡單的例子:

作者對效能做了對比,效能非常不錯。

go語言中slice的實現

slice是我們使用go語言時最經常使用的資料結構,所以我們還是有必要研究一下它的實現的,尤其是slice的擴容,具體實現參考src runtime slice.go。slice定義 type slice struct根據growslice函式的名稱,可以很容易的猜到這就是slice擴容的實現。if...

go語言中map的實現原理

map的迭代順序是不確定的,並且不同的雜湊函式實現可能導致不同的遍歷順序。在實踐中,遍歷的順序是隨機的,每一次遍歷的順序都不相同。這是故意的,每次都使用隨機的遍歷順序可以強制要求程式不會依賴具體的雜湊函式實現。待續。map的key必須可以比較 func不可以作為key,func 型別是不可比較的型別...

go 語言中的繼承

go 語言中可以通過匿名field來實現繼承的效果,type t1 struct func t t1 log func t t1 print type t2 struct t2 t2 可以通過t2.log 直接訪問t1的method,就像物件導向的繼承之後一樣訪問,不過這裡要注意的傳遞到log的是t...