前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >极端情况下收缩 Go 进程的线程数

极端情况下收缩 Go 进程的线程数

作者头像
范蠡
发布2020-12-15 11:23:48
7580
发布2020-12-15 11:23:48
举报
文章被收录于专栏:高性能服务器开发

在 Go 的 runtime 里有一些创建了就没法回收的东西。

之前在 这篇 里讲过 allgs 没法回收的问题。

除了 allgs 之外,当前 Go 创建的线程也是没法退出的,比如这个来自 xiaorui.cc 的例子,我简单做了个修改,能从网页看到线程:

代码语言:javascript
复制
package main


/*
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
void output(char *str) {
    usleep(1000000);
    printf("%s\n", str);
}
*/
import "C"
import "unsafe"


import "net/http"
import _ "net/http/pprof"


func init() {
 go http.ListenAndServe(":9999", nil)
}


func main() {
    for i := 0;i < 1000;i++ {
        go func(){
            str := "hello cgo"
            //change to char*
            cstr := C.CString(str)
            C.output(cstr)
            C.free(unsafe.Pointer(cstr))


        }()
    }
    select{}
}

可见 Goroutine 退出了,历史上创建的线程也是不会退出的。之前我也一直认为没有办法退出这些线程,不过这周被同事教育,还是有办法的。参考官方 issue 14592。文末有链接。

虽然问题直到现在依然没解决,但是这个 issue 里也提供了一种邪道解决办法,直接调用 LockOSThread,而不调用 Unlock,这样在退出的时候和当前 g 绑定的线程就会直接销毁:

把开头的程序改改,增加一个接口,killThread。

代码语言:javascript
复制
package main


/*
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
void output(char *str) {
    usleep(1000000);
    printf("%s\n", str);
}
*/
import "C"


import (
 "net/http"
 "unsafe"


 "log"
 _ "net/http/pprof"
 "runtime"
 "sync"
)


func init() {
 go http.ListenAndServe(":9999", nil)
}


func main() {
 for i := 0; i < 1000; i++ {
  go func() {
   str := "hello cgo"
   //change to char*
   cstr := C.CString(str)
   C.output(cstr)
   C.free(unsafe.Pointer(cstr))


  }()
 }
 killThreadService()
 select {}
}


func sayhello(wr http.ResponseWriter, r *http.Request) {
 KillOne()
}


func killThreadService() {
 http.HandleFunc("/", sayhello)
 err := http.ListenAndServe(":10003", nil)
 if err != nil {
  log.Fatal("ListenAndServe:", err)
 }
}


// KillOne kills a thread
func KillOne() {
 var wg sync.WaitGroup
 wg.Add(1)


 go func() {
  defer wg.Done()
  runtime.LockOSThread()
  return
 }()


 wg.Wait()
}


启动后,发现创建了 1k+ 线程,curl localhost:10003,可以发现线程数在逐渐降低。

[1] https://github.com/golang/go/issues/14592

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-12-09,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 高性能服务器开发 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档