Maison >développement back-end >Golang >Comment implémenter epoll dans Golang
Dans le système d'exploitation Linux, epoll est un mécanisme de notification d'événements d'E/S très efficace. Lorsque vous utilisez epoll, vous pouvez lier plusieurs descripteurs de fichiers à une seule instance d'epoll. L'instance d'epoll informera le programme des événements d'E/S qui se produisent sur tous les descripteurs de fichiers. Comparé à d'autres mécanismes de notification d'événements d'E/S tels que select et poll, epoll offre une plus grande efficacité et une surcharge moindre. Dans cet article, nous présenterons comment implémenter epoll dans Golang.
Sous Linux, chaque processus a sa propre table de descripteurs de fichiers Lorsque le processus doit effectuer une opération I/Durant O. , le fichier ou le socket correspondant doit être accessible via le descripteur de fichier. Lorsque le fichier ou le socket est prêt, le noyau avertira le processus. Cette notification est un événement d'E/S. Lorsqu'un événement d'E/S se produit, select et poll parcourront tous les ensembles de descripteurs de fichier, mais epoll est différent : il ne parcourra que l'ensemble de descripteurs de fichier où l'événement d'E/S s'est produit.
epoll se compose essentiellement de trois appels système : epoll_create, epoll_ctl et epoll_wait. epoll_create est utilisé pour créer une instance epoll, epoll_ctl est utilisé pour ajouter/supprimer/modifier des descripteurs de fichier à l'instance epoll, et epoll_wait est utilisé pour attendre que des événements se produisent sur le descripteur de fichier.
En golang, epoll est implémenté par le package net/netutil. Il est encapsulé sur la base des appels système epoll_create, epoll_ctl et epoll_wait. golang encapsule epoll dans le fichier internal/poll/epoll de netutil.
Lorsque Golang implémente epoll, il définit respectivement les types d'instance epoll epollServer et epollDesc. Parmi eux, epollServer contient une instance epoll, qui est utilisée pour stocker les descripteurs de fichiers et les événements d'E/S ; epollDesc est utilisé pour représenter un descripteur de fichier et les événements d'E/S associés.
Jetons d'abord un coup d'œil à l'implémentation d'epollServer. epollServer contient les champs suivants :
type epollServer struct { // events 是一个数组,用于存储返回的 I/O 事件 events []syscall.EpollEvent // epollFd 是 epoll 实例的文件描述符 epollFd int // fds 用于存储文件描述符和对应的 epollDesc fds map[int]*epollDesc }
Tout d'abord, afin de créer une instance epollServer, vous devez appeler la fonction newEpollServer fournie par golang.
func newEpollServer() (ep *epollServer, err error) { // 创建 epoll 实例 ep = &epollServer{ events: make([]syscall.EpollEvent, epollServerBlock), fds: make(map[int]*epollDesc), } ep.epollFd, err = syscall.EpollCreate1(0) if err != nil { return nil, err } // 将 epoll 实例添加到 epollServer 的文件描述符映射表中 ep.fds[ep.epollFd] = &epollDesc{ep, syscall.EPOLLIN} return ep, nil }
Nous pouvons voir que lors de la création d'une instance epollServer, une instance epoll sera d'abord créée via l'appel syscall.EpollCreate1(0), puis ajoutée à la table de mappage des descripteurs de fichiers d'epollServer .
Ensuite, nous pouvons ajouter un descripteur de fichier à l'instance epollServer via la méthode addFD.
func (ep *epollServer) addFD(fd int, mode int) error { // 设置文件描述符的非阻塞模式 if err := syscall.SetNonblock(fd, true); err != nil { return err } // 将文件描述符的 I/O 事件添加到 epoll 实例中 ev := syscall.EpollEvent{Fd: int32(fd), Events: syscall.EPOLLIN | syscall.EPOLLOUT} if err := syscall.EpollCtl(ep.epollFd, syscall.EPOLL_CTL_ADD, fd, &ev); err != nil { return err } // 将文件描述符和 epollDesc 添加到文件描述符映射表中 ep.fds[fd] = &epollDesc{ep, mode} return nil }
Dans la méthode addFD, définissez d'abord le descripteur de fichier en mode non bloquant, puis ajoutez l'événement d'E/S du descripteur de fichier à l'instance epoll. Enfin, ajoutez le descripteur de fichier et l'epollDesc correspondant à la table de mappage du descripteur de fichier.
Enfin, nous pouvons attendre les événements d'E/S qui se produisent sur le descripteur de fichier via la méthode wait.
func (ep *epollServer) wait(ms int) ([]syscall.EpollEvent, error) { if ms < 0 { ms = -1 } // 等待发生 I/O 事件 nEvents, err := syscall.EpollWait(ep.epollFd, ep.events, ms) if err != nil { return nil, err } // 返回发生的 I/O 事件 return ep.events[:nEvents], nil }
Maintenant, nous avons compris comment epollServer est implémenté dans golang. Nous présenterons ensuite la méthode d’implémentation de epollDesc.
epollDesc est utilisé pour représenter un descripteur de fichier et son événement d'E/S correspondant. Son implémentation est très simple, ne nécessitant qu'un pointeur vers epollServer et un entier représentant l'événement d'E/S.
type epollDesc struct { srv *epollServer mode int }
Dans cet article, nous avons présenté comment utiliser epoll dans Golang pour implémenter un mécanisme efficace de notification d'événements d'E/S. Nous avons présenté en détail les principes de base de l’implémentation par epoll et golang d’epollServer et epollDesc. Je pense qu'en lisant cet article, vous pourrez mieux comprendre l'implémentation d'epoll dans Golang et fournir une référence pour choisir le mécanisme de notification d'événements d'E/S approprié pour votre projet.
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!