为了账号安全,请及时绑定邮箱和手机立即绑定

runtime/cgo: pthread_create failed: 资源暂时不可用

runtime/cgo: pthread_create failed: 资源暂时不可用

Go
一只甜甜圈 2022-05-10 17:15:02
我目前有这个功能,通过 ffmpeg 管道传输多个 youtubedl 命令,然后将 ffmpeg 的输出管道传输到 HTTP 客户端。func pipeThruFfmpegToMp4(vi *VideoInfo, rw web.ResponseWriter) error {    var ffmpeg *exec.Cmd    ffmpeg = exec.Command(        "ffmpeg",        "-i", "-",        "-i", "pipe:3",        "-c:v", "copy", "-c:a", "copy",        "-preset", "veryfast",        "-metadata", fmt.Sprintf(`title=%s`, vi.GetTitle()),        "-movflags", "frag_keyframe+empty_moov",        "-f", "mp4",        "-")    youtubevideo := exec.Command(YoutubeDLPath, "-c", "-f", fmt.Sprintf("%s/bestvideo[ext=mp4]/bestvideo/best", vi.GetFormat()), "--no-cache-dir", "--restrict-filenames", "--hls-prefer-native", "-o", "-", fmt.Sprintf("%s", vi.GetVideoUrl()))    fmt.Println(youtubevideo)    youtube := exec.Command(YoutubeDLPath, "-c", "-f", "bestaudio[ext=m4a]/bestaudio/best", "--no-cache-dir", "--restrict-filenames", "--hls-prefer-native", "-o", "-", fmt.Sprintf("%s", vi.GetVideoUrl()))    fmt.Println(youtube)    var ytvbuf, ytbuf, ffbuf bytes.Buffer    youtubevideo.Stderr = &ytvbuf    youtube.Stderr = &ytbuf    ffmpeg.Stderr = &ffbuf    video, err := youtubevideo.StdoutPipe()    if err != nil {        log.Printf("pipeThruFfmpegToMp4: %v\n", err)        return err    }    pipe3, err := youtube.StdoutPipe()    if err != nil {        log.Printf("pipeThruFfmpegToMp4: %v\n", err)        return err    }    ffmpeg.Stdin = video    ffmpeg.ExtraFiles = []*os.File{pipe3.(*os.File)}    ffmpeg.Stdout = rw    // Headers sent, no turning back now    rw.Header().Set("Content-Type", "video/mp4")    rw.Header().Set("Content-Disposition", fmt.Sprintf("attachment;filename=\"%s.mp4\"", vi.GetSlug()))    rw.Flush()    ffmpeg.Start()    youtubevideo.Start()    youtube.Start()    ffmpeg.Wait()    youtubevideo.Wait()    youtube.Wait()问题是一切运行正常,但过了一会儿,内存开始填满服务器,直到它出现错误runtime/cgo: pthread_create failed: Resource temporarily unavailable我不确定这是否是内存泄漏,或者 youtube-dl 的任一实例是否未正确关闭,或者 ffmpeg 是否未正确关闭并且随着程序运行更多而消耗越来越多的内存,直到程序因此错误而崩溃
查看完整描述

2 回答

?
慕标琳琳

TA贡献1830条经验 获得超9个赞

我有时会遇到问题,您的代码不会终止youtube-dl进程。视频被转换,但过程被保留。作为第一个指标,观察进程计数,如下所示:


ps | grep youtube-dl | wc -l

可以让子进程超时,对于一个子进程,这看起来像这样:


package main


import (

    "bytes"

    "fmt"

    "os/exec"

    "time"

)


func main() {

    // Sleep is used, so we can control how long it runs.

    cmd := exec.Command("sleep", "2")


    // Use a bytes.Buffer to get the output

    var buf bytes.Buffer

    cmd.Stdout = &buf


    cmd.Start()


    // Use a channel to signal completion so we can use a select statement

    done := make(chan error)

    go func() { done <- cmd.Wait() }()


    // Start a timer, should be higher for your video conversion, 

    // I suggest you use a value that fits both your videos and server capabilities

    timeout := time.After(2 * time.Second)


    // The select statement allows us to execute based on which channel

    // we get a message from first.

    select {

    case <-timeout:

        // Timeout happened first, kill the process and print a message.

        cmd.Process.Kill()

        fmt.Println("Command timed out")

    case err := <-done:

        // Command completed before timeout. Print output and error if it exists.

        fmt.Println("Output:", buf.String())

        if err != nil {

            fmt.Println("Non-zero exit code:", err)

        }

    }

}

在你的情况下,你可以更换


    ffmpeg.Start()

    youtubevideo.Start()

    youtube.Start()

    ffmpeg.Wait()

    youtubevideo.Wait()

    youtube.Wait()


    ffmpeg.Start()

    youtubevideo.Start()

    youtube.Start()

    commands := 3


    done := make(chan error)

    go func() { done <- ffmpeg.Wait() }()

    go func() { done <- youtubevideo.Wait() }()

    go func() { done <- youtube.Wait() }()


    timeout := time.After(1 * time.Hour)


Loop:

    for {

        select {

        case <-timeout:

            ffmpeg.Process.Kill()

            youtubevideo.Process.Kill()

            youtube.Process.Kill()

            log.Println("Conversion timed out")

            break Loop

        case err := <-done:

            if err != nil {

                log.Println("Non-zero exit code:", err)

            }

            commands = commands - 1

            if commands == 0 {

                break Loop

            }

        }

    }


查看完整回答
反对 回复 2022-05-10
?
富国沪深

TA贡献1790条经验 获得超9个赞

因此,经过一些调试并在凯文的回答的帮助下。成功后好像youtube-dl没有关闭。


鉴于如果ffmpeg完成,那么让youtube-dl实例运行没有任何意义,并且由于Wait()函数正在等待youtube-dl完成,但它似乎从未发送完成信号,所以我继续并不得不添加一个 kill 来杀死子子进程。


所以我不得不添加改变这个


    ffmpeg.Start()

    youtubevideo.Start()

    youtube.Start()

    ffmpeg.Wait()

    youtubevideo.Wait()

    youtube.Wait()

对此


    youtube.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}

    youtubevideo.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}

    ffmpeg.Start()

    youtubevideo.Start()

    youtube.Start()

    ffmpeg.Wait()

    syscall.Kill(-youtube.Process.Pid, syscall.SIGKILL)

    syscall.Kill(-youtubevideo.Process.Pid, syscall.SIGKILL)

    youtubevideo.Wait()

    youtube.Wait()

请注意,因为它似乎产生了某种子子youtube.Process.Kill()进程,实际上并没有杀死该进程,这就是我必须使用的原因syscall,而且Setpgid: true


查看完整回答
反对 回复 2022-05-10
  • 2 回答
  • 0 关注
  • 1217 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号