最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Golang中NetPoll機(jī)制的實(shí)現(xiàn)

 更新時(shí)間:2025年12月23日 11:13:46   作者:AI吳界  
本文主要介紹了Golang中NetPoll機(jī)制的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

Linux 網(wǎng)絡(luò)IO

Linux 的阻塞網(wǎng)絡(luò) I/O (輸入/輸出) 是指在進(jìn)行網(wǎng)絡(luò)操作(如 read() 或 write())時(shí),如果操作無法立即完成,調(diào)用線程將被操作系統(tǒng)“阻塞”,直到操作成功或失敗才返回。它屬于同步 I/O 模型的一種,與之相對(duì)的是非阻塞 I/O。

int listenfd = socket(AF_INET, SOCK_STREAM, 0);

struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htonl(INADDR_ANY); // 綁定到所有可用接口
server_addr.sin_port = htons(8080); // 綁定到 8080 端口
bind(listenfd, (struct sockaddr *)&server_addr, sizeof(server_addr));

listen(listenfd, 5); // 允許 5 個(gè)待處理的連接

// 阻塞等待
struct sockaddr_in client_addr;
socklen_t client_addr_len = sizeof(client_addr);
int connectfd = accept(listenfd, (struct sockaddr *)&client_addr, &client_addr_len);

Linux 非阻塞IO Select、Poll、Epoll

核心機(jī)制:這些系統(tǒng)調(diào)用讓用戶進(jìn)程在調(diào)用前,能預(yù)先指定一系列要監(jiān)控的文件描述符。當(dāng)一個(gè)或多個(gè)文件描述符準(zhǔn)備好進(jìn)行讀寫操作時(shí),系統(tǒng)會(huì)通知用戶進(jìn)程。

輪詢與事件驅(qū)動(dòng)
select 和 poll: 它們采用輪詢方式,每次都檢查所有傳入的文件描述符集合來判斷哪些是活躍的。

(1)select==>時(shí)間復(fù)雜度O(n)

它僅僅知道了,有I/O事件發(fā)生了,卻并不知道是哪那幾個(gè)流(可能有一個(gè),多個(gè),甚至全部),我們只能無差別輪詢所有流,找出能讀出數(shù)據(jù),或者寫入數(shù)據(jù)的流,對(duì)他們進(jìn)行操作。所以select具有O(n)的無差別輪詢復(fù)雜度,同時(shí)處理的流越多,無差別輪詢時(shí)間就越長(zhǎng)。

(2)poll==>時(shí)間復(fù)雜度O(n)

poll本質(zhì)上和select沒有區(qū)別,它將用戶傳入的數(shù)組拷貝到內(nèi)核空間,然后查詢每個(gè)fd對(duì)應(yīng)的設(shè)備狀態(tài), 但是它沒有最大連接數(shù)的限制,原因是它是基于鏈表來存儲(chǔ)的.

(3)epoll==>時(shí)間復(fù)雜度O(1)

epoll: 它采用事件驅(qū)動(dòng)模型,通過內(nèi)核的回調(diào)機(jī)制,只在需要時(shí)通知用戶進(jìn)程,效率更高,尤其是在處理大量并發(fā)連接時(shí)。epoll 機(jī)制通過在內(nèi)核中維護(hù)一個(gè)就緒列表,當(dāng)數(shù)據(jù)到達(dá)時(shí),將對(duì)應(yīng)的節(jié)點(diǎn)加入就緒列表,然后喚醒等待的用戶進(jìn)程,從而避免了不必要的輪詢

Golang 中Epoll 應(yīng)用

一個(gè)簡(jiǎn)單的網(wǎng)絡(luò)IO

// 啟動(dòng) tcp server 代碼示例
func main() {
	/*
		- 創(chuàng)建 tcp 端口監(jiān)聽器
		    - 創(chuàng)建 socket fd,bind、accept
			- 創(chuàng)建 epoll 事件表(epoll_create)
			- socket fd 注冊(cè)到 epoll 事件表(epoll_ctl:add)

	*/
	l, _ := net.Listen("tcp", ":8080")
	// eventloop reactor 模型
	for {
		/*
			- 等待 tcp 連接到達(dá)
			    - loop + 非阻塞模式調(diào)用 accept
				- 若未就緒,則通過 gopark 進(jìn)行阻塞
				- 等待 netpoller 輪詢喚醒
				     - 檢查是否有 io 事件就緒(epoll_wait——nonblock)
					 - 若發(fā)現(xiàn)事件就緒 通過 goready 喚醒 g
				- accept 獲取 conn fd 后注冊(cè)到 epoll 事件表(epoll_ctl:add)
				- 返回 conn
		*/
		conn, _ := l.Accept()
		// goroutine per conn
		go serve(conn)
	}
}

// 處理一筆到來的 tcp 連接
func serve(conn net.Conn) {
	/*
		- 關(guān)閉 conn
		   - 從 epoll 事件表中移除該 fd(epoll_ctl:remove)
		   - 銷毀該 fd
	*/
	defer conn.Close()
	var buf []byte
	/*
		- 讀取連接中的數(shù)據(jù)
		   - loop + 非阻塞模式調(diào)用 recv (read)
		   - 若未就緒,則通過 gopark 進(jìn)行阻塞
		   - 等待 netpoller 輪詢喚醒
			    - 檢查是否有 io 事件就緒(epoll_wait——nonblock)
				- 若發(fā)現(xiàn)事件就緒 通過 goready 喚醒 g
	*/
	_, _ = conn.Read(buf)
	/*
		- 向連接中寫入數(shù)據(jù)
		   - loop + 非阻塞模式調(diào)用 writev (write)
		   - 若未就緒,則通過 gopark 進(jìn)行阻塞
		   - 等待 netpoller 輪詢喚醒
			    - 檢查是否有 io 事件就緒(epoll_wait:nonblock)
				- 若發(fā)現(xiàn)事件就緒 通過 goready 喚醒 g
	*/
	_, _ = conn.Write(buf)
}

1、調(diào)用Listen方法,通過epoll_create 初始化事件表, 創(chuàng)建 socket fd, 通過epoll_ctl 將socket fd注冊(cè)到Epoll事件表, 監(jiān)聽就緒事件,等待遠(yuǎn)端連接。如果有遠(yuǎn)端連接,則會(huì)在內(nèi)核空間執(zhí)行回調(diào)函數(shù),將socket fd放入就緒列表中

 // 在 epoll 事件表中注冊(cè)監(jiān)聽 r 的讀就緒事件
	ev := epollevent{
		events: _EPOLLIN,
	}

2、調(diào)用Accept方法,非阻塞調(diào)用Epoll Wait,獲取當(dāng)前監(jiān)聽的fd是否有就緒的socket fd
2.1、如果沒有則將當(dāng)前的goroutine阻塞,并掛載在socket fd 對(duì)應(yīng)的polldesc的rg等待鏈表中,等待環(huán)境
2.2、如果有,則獲取conn fd返回給用戶程序

// Accept wraps the accept network call.
func (fd *FD) Accept() (int, syscall.Sockaddr, string, error) {
        // ...
        for {
                // 以nonblock 模式發(fā)起一次 syscall accept 嘗試接收到來的 conn
		s, rsa, errcall, err := accept(fd.Sysfd)
                // 接收conn成功,直接返回結(jié)果
                if err == nil {
			return s, rsa, "", err
		}
		switch err {
                // 中斷類錯(cuò)誤直接忽略
		case syscall.EINTR:
			continue
                // 當(dāng)前未有到達(dá)的conn 
		case syscall.EAGAIN:
       // 走入 poll_wait 流程,并標(biāo)識(shí)關(guān)心的是 socket fd 的讀就緒事件
       // (當(dāng)conn 到達(dá)時(shí),表現(xiàn)為 socket fd 可讀)
			if fd.pd.pollable() {
         // 倘若讀操作未就緒,當(dāng)前g 會(huì) park 阻塞在該方法內(nèi)部,直到因超時(shí)或者事件就緒而被 netpoll ready 喚醒
				if err = fd.pd.waitRead(fd.isFile); err == nil {
					continue
				}
			}
                        // ...
		}
                // ...
	}
}

// 指定 mode 為 r 標(biāo)識(shí)等待的是讀就緒事件,然后走入更底層的 poll_wait 流程
func (pd *pollDesc) waitRead(isFile bool) error {
	return pd.wait('r', isFile)
}

3、調(diào)用Read、Write方法。非阻塞調(diào)用Epoll Wait,關(guān)心conn fd上是否有讀就緒事件或者寫就緒事件
3.1、如果 conn fd 下讀操作尚未就緒(尚無數(shù)據(jù)到達(dá)),則會(huì)執(zhí)行 poll wait 將當(dāng)前 g 阻塞并掛載到 conn fd 對(duì)應(yīng) pollDesc 的 rg 中
3.2、如果 conn fd 下寫操作尚未就緒(緩沖區(qū)空間不足),則會(huì)執(zhí)行 poll wait 將當(dāng)前 g 阻塞并掛載到 conn fd 對(duì)應(yīng) pollDesc 的wg中

// Read implements io.Reader.
func (fd *FD) Read(p []byte) (int, error) {
        // ... 
	for {
                // 以非阻塞模式執(zhí)行一次syscall read 操作 
		n, err := ignoringEINTRIO(syscall.Read, fd.Sysfd, p)
		if err != nil {
			n = 0
                        // 走入 poll_wait 流程,并標(biāo)識(shí)關(guān)心的是該 fd 的讀就緒事件
			if err == syscall.EAGAIN && fd.pd.pollable() {
                                // 倘若讀操作未就緒,當(dāng)前g 會(huì) park 阻塞在該方法內(nèi)部,直到因超時(shí)或者事件就緒而被 netpoll ready 喚醒
				if err = fd.pd.waitRead(fd.isFile); err == nil {
					continue
				}
			}
		}
		err = fd.eofError(n, err)
		return n, err
	}
}

4、小結(jié)
可以看到,一個(gè)連接的數(shù)據(jù)讀寫,如果條件不滿足,goroutine都會(huì)掛起并掛載到pollDesc的rg、wg中,但此時(shí)用戶程序主線程不會(huì)阻塞,而是等待底層數(shù)據(jù)到達(dá)后,再進(jìn)行處理。

NetPoll的調(diào)度

由上可知,當(dāng) g 發(fā)現(xiàn)關(guān)心的 io 事件未就緒時(shí),會(huì)通過 gopark 操作將自身陷入阻塞,并且將 g 掛載在 pollDesc 的 rg/wg 中, 而本小節(jié)介紹的 net_poll 流程就負(fù)責(zé)輪詢獲取已就緒 pollDesc 對(duì)應(yīng)的 g,將其返回給上游的 gmp 調(diào)度系統(tǒng),對(duì)其進(jìn)行喚醒和調(diào)度.

Golang GMP模型觸發(fā)netpoll時(shí)機(jī)
1、M在尋找可用的Goroutine時(shí),在本地和全局隊(duì)列上沒有找到,會(huì)調(diào)用netpoll處理網(wǎng)絡(luò)IO

// gmp 核心調(diào)度流程:g0 為當(dāng)前 p 找到下一個(gè)調(diào)度的  g
    /*
        pick g 的核心邏輯:
             1)每調(diào)度 61 次,需要專門嘗試處理一次全局隊(duì)列(防止饑餓)
             2)嘗試從本地隊(duì)列中獲取 g
             3)嘗試從全局隊(duì)列中獲取 g
             4)以【非阻塞模式】調(diào)度 netpoll 流程,獲取所有需要喚醒的 g 進(jìn)行喚醒,并獲取其中的首個(gè)g
             5)從其他 p 中竊取一半的 g 填充到本地隊(duì)列
             6)仍找不到合適的 g,則協(xié)助 gc 
             7)以【阻塞或者超時(shí)】模式,調(diào)度netpoll 流程(全局僅有一個(gè) p 能走入此分支)
             8)當(dāng)前m 添加到全局隊(duì)列的空閑隊(duì)列中,停止當(dāng)前 m
    */

func findRunnable() (gp *g, inheritTime, tryWakeP bool) {
    // ..
    /*
      同時(shí)滿足下述三個(gè)條件,發(fā)起一次【非阻塞模式】的 netpoll 流程:
        - epoll事件表初始化過
        - 有 g 在等待io 就緒事件
        - 沒有空閑 p 在以【阻塞或超時(shí)】模式發(fā)起 netpoll 流程
    */ 
    if netpollinited() && atomic.Load(&netpollWaiters) > 0 && atomic.Load64(&sched.lastpoll) != 0 {
                // 以非阻塞模式發(fā)起一輪 netpoll,如果有 g 需要喚醒,一一喚醒之,并返回首個(gè) g 給上層進(jìn)行調(diào)度
		if list := netpoll(0); !list.empty() { // non-blocking
                // 獲取就緒 g 隊(duì)列中的首個(gè) g
                        gp := list.pop()
                        // 將就緒 g 隊(duì)列中其余 g 一一置為就緒態(tài),并添加到全局隊(duì)列
			injectglist(&list)
                        // 把首個(gè)g 也置為就緒態(tài)
			casgstatus(gp, _Gwaiting, _Grunnable)
                         // ... 
                         //返回 g 給當(dāng)前 p進(jìn)行調(diào)度
			return gp, false, false
		}
	}
 
    // ...
    /*
        同時(shí)滿足下述三個(gè)條件,發(fā)起一次【阻塞或超時(shí)模式】的 netpoll 流程:
            - epoll事件表初始化過
            - 有 g 在等待io 就緒事件
            - 沒有空閑 p 在以【阻塞或超時(shí)】模式發(fā)起 netpoll 流程
    */	
	if netpollinited() && (atomic.Load(&netpollWaiters) > 0 || pollUntil != 0) && atomic.Xchg64(&sched.lastpoll, 0) != 0 {
                // 默認(rèn)為阻塞模式 
		delay := int64(-1)
                // 存在定時(shí)時(shí)間,則設(shè)為超時(shí)模式
		if pollUntil != 0 {
			delay = pollUntil - now
                        // ... 
		}
                // 以【阻塞或超時(shí)模式】發(fā)起一輪 netpoll
		list := netpoll(delay) // block until new work is available 
	} 
        // ... 
}

2、Sysmon 定時(shí)會(huì)調(diào)用netpoll處理網(wǎng)絡(luò)IO

// The main goroutine.
func main() {
        // ...
        // 新建一個(gè) m,直接運(yùn)行 sysmon 函數(shù)
	systemstack(func() {
		newm(sysmon, nil, -1)
	})

         // ...
}

// 全局唯一監(jiān)控線程的執(zhí)行函數(shù)
func sysmon() {
        // ...
	for {
              // ...
        /*
        同時(shí)滿足下述三個(gè)條件,發(fā)起一次【非阻塞模式】的 netpoll 流程:
            - epoll事件表初始化過
            - 沒有空閑 p 在以【阻塞或超時(shí)】模式發(fā)起 netpoll 流程
            - 距離上一次發(fā)起 netpoll 流程的時(shí)間間隔已超過 10 ms
        */ 
		lastpoll := int64(atomic.Load64(&sched.lastpoll))
		if netpollinited() && lastpoll != 0 && lastpoll+10*1000*1000 < now {
                        // 以非阻塞模式發(fā)起 netpoll
			list := netpoll(0) // non-blocking - returns list of goroutines
                        // 獲取到的  g 置為就緒態(tài)并添加到全局隊(duì)列中
			if !list.empty() {
                                // ...
				injectglist(&list)
                                // ...
			}
		}
                // ... 
	}
}

3、gc并發(fā)標(biāo)記的流程

func startTheWorldWithSema(emitTraceEvent bool) int64 {
        // 斷言世界已停止
	assertWorldStopped()
        // ...
        // 如果 epoll 事件表初始化過,則以非阻塞模式執(zhí)行一次 netpoll
	if netpollinited() {
                // 所有取得的 g 置為就緒態(tài)并添加到全局隊(duì)列
		list := netpoll(0) // non-blocking
		injectglist(&list)
	}
        // ...
}

當(dāng)上述條件成立時(shí),Netpoll執(zhí)行 epoll_wait 操作,獲取就緒的 io 事件 list. 一輪最多獲取 128 個(gè),根據(jù)就緒事件類型,將 mode 分為 w(寫就緒事件)和 r(讀就緒事件)。獲取 pollDesc 實(shí)例中 rg或者wg中的 g 實(shí)例,一并返回GMP進(jìn)行調(diào)度

// netpoll checks for ready network connections.
// Returns list of goroutines that become runnable.
/*
    - netpoll 流程用于輪詢檢查是否有就緒的 io 事件
    - 如果有就緒 io 事件,還需要檢查是否有 pollDesc 中的 g 關(guān)心該事件
    - 找到所有關(guān)心該就緒 io 事件的 g,添加到 list 中返回給上游進(jìn)行 goready 喚醒
*/
func netpoll(delay int64) gList {
     /*
        根據(jù)傳入的 delay 參數(shù),決定調(diào)用 epoll_wait 的模式
            - delay < 0:設(shè)為 -1 阻塞模式(在 gmp 調(diào)度流程中,如果某個(gè) p 遲遲獲取不到可執(zhí)行的 g 時(shí),會(huì)通過該模式,使得 thread 陷入阻塞態(tài),但該情況全局最多僅有一例)
            - delay = 0:設(shè)為 0 非阻塞模式(通常情況下為此模式,包括 gmp 常規(guī)調(diào)度流程、gc 以及全局監(jiān)控線程 sysmon 都是以此模式觸發(fā)的 netpoll 流程)
            - delay > 0:設(shè)為超時(shí)模式(在 gmp 調(diào)度流程中,如果某個(gè) p 遲遲獲取不到可執(zhí)行的 g 時(shí),并且通過 timer 啟動(dòng)了定時(shí)任務(wù)時(shí),會(huì)令 thread 以超時(shí)模式執(zhí)行 epoll_wait 操作)
    */
     var waitms int32
     if delay < 0 {
		waitms = -1
     } else if delay == 0 {
		waitms = 0
     // 針對(duì) delay 時(shí)長(zhǎng)取整
     } else if delay < 1e6 {
		waitms = 1
     } else if delay < 1e15 {
		waitms = int32(delay / 1e6)
     } else {
     // 1e9 ms == ~11.5 days.
		waitms = 1e9
     }
     // 一次最多接收 128 個(gè) io 就緒事件	
     var events [128]epollevent
retry:
     // 以指定模式,調(diào)用 epoll_wait 指令
	n := epollwait(epfd, &events[0], int32(len(events)), waitms)
     // ...
 
     // 遍歷就緒的每個(gè) io 事件	
     var toRun gList
     for i := int32(0); i < n; i++ {
	   ev := &events[i]
           if ev.events == 0 {
                continue
           }

           // pipe 接收端的信號(hào)量處理
           if *(**uintptr)(unsafe.Pointer(&ev.data)) == &netpollBreakRd {
           // ...
            }
 
            /*
             根據(jù) io 事件類型,標(biāo)識(shí)出 mode:
                 - EPOLL_IN -> r;
                 - EPOLL_OUT -> w;
                 - 錯(cuò)誤或者中斷事件 -> r & w;
             */
            var mode int32
            if ev.events&(_EPOLLIN|_EPOLLRDHUP|_EPOLLHUP|_EPOLLERR) != 0 {
			mode += 'r'
            }
            if ev.events&(_EPOLLOUT|_EPOLLHUP|_EPOLLERR) != 0 {
			mode += 'w'
            }
            // 根據(jù) epollevent.data 獲取到監(jiān)聽了該事件的 pollDesc 實(shí)例
            if mode != 0 {
			pd := *(**pollDesc)(unsafe.Pointer(&ev.data))
                        // ...			
                        // 嘗試針對(duì)對(duì)應(yīng) pollDesc 進(jìn)行喚醒操作
                        netpollready(&toRun, pd, mode)
            }
      }
      return toRun
}




/*
    epollwait 操作:
        - epfd:epoll 事件表 fd 句柄
        - ev:用于承載就緒 epoll event 的容器
        - nev:ev 的容量
        - timeout:
            - -1:阻塞模式
            - 0:非阻塞模式:
            - >0:超時(shí)模式. 單位 ms
        - 返回值 int32:就緒的 event 數(shù)量
*/
func epollwait(epfd int32, ev *epollevent, nev, timeout int32) int32





// It declares that the fd associated with pd is ready for I/O.
// The toRun argument is used to build a list of goroutines to return
// from netpoll. The mode argument is 'r', 'w', or 'r'+'w' to indicate
/*
 根據(jù) pd 以及 mode 標(biāo)識(shí)的 io 就緒事件,獲取需要進(jìn)行 ready 喚醒的 g list
 對(duì)應(yīng) g 會(huì)存儲(chǔ)到 toRun 這個(gè) list 容器當(dāng)中
*/
func netpollready(toRun *gList, pd *pollDesc, mode int32) {
	var rg, wg *g
	if mode == 'r' || mode == 'r'+'w' {
        // 倘若到達(dá)事件包含讀就緒,嘗試獲取需要 ready 喚醒的 g
		rg = netpollunblock(pd, 'r', true)
	}
	if mode == 'w' || mode == 'r'+'w' {
 // 倘若到達(dá)事件包含寫就緒,嘗試獲取需要 ready 喚醒的 g
		wg = netpollunblock(pd, 'w', true)
	}
 // 找到需要喚醒的 g,添加到 glist 中返回給上層
	if rg != nil {
		toRun.push(rg)
	}
	if wg != nil {
		toRun.push(wg)
	}
}




/*
 根據(jù)指定的就緒io 事件類型以及 pollDesc,判斷是否有 g 需要被喚醒. 若返回結(jié)果非空,則為需要喚醒的 g
*/
func netpollunblock(pd *pollDesc, mode int32, ioready bool) *g {
        // 根據(jù) io 事件類型,獲取 pollDesc 中對(duì)應(yīng)的狀態(tài)標(biāo)識(shí)器
        gpp := &pd.rg
	if mode == 'w' {
		gpp = &pd.wg
	}

	for {
                // 從 gpp 中取出值,此時(shí)該值應(yīng)該為調(diào)用過 park 操作的 g
		old := gpp.Load()
                 // ... 
		if ioready {
			new = pdReady
		}
                // 通過 cas 操作,將 gpp 值由 g 置換成 pdReady
		if gpp.CompareAndSwap(old, new) {
                        // 返回需要喚醒的 g 
			return (*g)(unsafe.Pointer(old))
		}
	}
}

到此這篇關(guān)于Golang中NetPoll機(jī)制的實(shí)現(xiàn) 的文章就介紹到這了,更多相關(guān)Golang NetPoll 內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Go語言反射使用及優(yōu)缺點(diǎn)總結(jié)

    Go語言反射使用及優(yōu)缺點(diǎn)總結(jié)

    反射是一種讓程序在運(yùn)行時(shí)自?。╥ntrospect)和修改自身結(jié)構(gòu)和行為的機(jī)制,這篇文章主要介紹了Go語言反射使用及優(yōu)缺點(diǎn)的相關(guān)資料,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2026-01-01
  • go語言實(shí)現(xiàn)二叉樹的序例化與反序列化

    go語言實(shí)現(xiàn)二叉樹的序例化與反序列化

    這篇文章主要介紹了go語言實(shí)現(xiàn)二叉樹的序例化與反序列化,文章圍繞主題展開詳細(xì)內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下
    2022-05-05
  • golang之log rotate詳解

    golang之log rotate詳解

    下面小編就為大家?guī)硪黄猤olang之log rotate詳解。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-06-06
  • goland Duration 和time的區(qū)別說明

    goland Duration 和time的區(qū)別說明

    這篇文章主要介紹了goland Duration 和time的區(qū)別說明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2020-12-12
  • 基于Go語言開發(fā)篇一個(gè)命令行進(jìn)程監(jiān)控工具

    基于Go語言開發(fā)篇一個(gè)命令行進(jìn)程監(jiān)控工具

    在生產(chǎn)和開發(fā)環(huán)境中,監(jiān)控關(guān)鍵進(jìn)程的存活與資源使用是非常常見的需求,本篇將開發(fā)一個(gè)輕量級(jí)的命令行進(jìn)程監(jiān)控工具,感興趣的小伙伴可以了解下
    2025-09-09
  • go中switch語句的用法詳解

    go中switch語句的用法詳解

    在Go中的switch語句類似于C、C++、Java、JavaScript和PHP中的switch語句,不同之處在于它只執(zhí)行匹配的case,因此不需要使用break語句,下面我們就一起來學(xué)習(xí)一下switch語句的具體使用吧
    2023-09-09
  • Go語言實(shí)現(xiàn)對(duì)XML的讀取和修改

    Go語言實(shí)現(xiàn)對(duì)XML的讀取和修改

    這篇文章主要為大家詳細(xì)介紹了Go語言實(shí)現(xiàn)對(duì)XML的讀取和修改的相關(guān)知識(shí),文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2023-12-12
  • 使用Singleflight實(shí)現(xiàn)Golang代碼優(yōu)化

    使用Singleflight實(shí)現(xiàn)Golang代碼優(yōu)化

    有許多方法可以優(yōu)化代碼以提高效率,減少運(yùn)行進(jìn)程就是其中之一,本文我們就來學(xué)習(xí)一下如何通過使用一個(gè)Go包Singleflight來減少重復(fù)進(jìn)程,從而優(yōu)化Go代碼吧
    2023-09-09
  • Golang關(guān)鍵字select的常用用法總結(jié)

    Golang關(guān)鍵字select的常用用法總結(jié)

    這篇文章主要為大家詳細(xì)介紹了golang中select關(guān)鍵字的常用用法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-10-10
  • Golang 發(fā)送http請(qǐng)求時(shí)設(shè)置header的實(shí)現(xiàn)

    Golang 發(fā)送http請(qǐng)求時(shí)設(shè)置header的實(shí)現(xiàn)

    這篇文章主要介紹了Golang 發(fā)送http請(qǐng)求時(shí)設(shè)置header的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-02-02

最新評(píng)論

综艺| 稻城县| 遵义县| 屯门区| 陈巴尔虎旗| 体育| 哈巴河县| 察隅县| 乌鲁木齐市| 延吉市| 乐陵市| 汽车| 仁寿县| 卢氏县| 阿克| 大余县| 三河市| 郁南县| 奈曼旗| 祁东县| 财经| 营口市| 岳阳市| 民勤县| 治县。| 麻栗坡县| 泰和县| 枣阳市| 特克斯县| 长汀县| 锦屏县| 乌恰县| 双辽市| 泌阳县| 金堂县| 噶尔县| 交城县| 无锡市| 克东县| 高邮市| 白山市|