首页 > 解决方案 > 读取 /dev/gpiomem 时 CPU 使用率高

问题描述

我的 Golang 代码中有什么东西会导致 CPU 使用率过高吗?

该代码应读取 Raspberry Pi 4 (4GB) 上 GPIO 引脚上的按钮,并在按下时将 RE​​ST 发布消息发送到另一个程序。

我尝试使用更多睡眠和不睡眠,我尝试更改代码以在引脚上使用下降沿检测方法。没有什么改变高 CPU 使用率。

在此处输入图像描述


import (
    "fmt"
    "github.com/stianeikeland/go-rpio"
    "os"
    "io/ioutil"
    "net/http"
    "strings"
    "time"
)

func main() {

    fmt.Println("Starting Stream Control 0.1")

    pinOpenError := rpio.Open()

    if pinOpenError != nil {
        fmt.Println("Pin Open Error: ", pinOpenError.Error())
        os.Exit(1)
    }

    pin := rpio.Pin(18)
    pin.Input()
    pin.PullUp()

    var PID string
    start := time.Now()

    StreamRunning := false;

    fmt.Println("Reading and Controlling")
    for {
        res := pin.Read()
        if res == 0 {
            if StreamRunning == false  && time.Since(start).Seconds() > 10{
            
            var StartStreamError error
            PID, StartStreamError = StartStream()
            if StartStreamError != nil {
                fmt.Println("Start Stream Error: ", StartStreamError.Error())
            }
            fmt.Println("PID = " + PID)

            start = time.Now()
            StreamRunning = true;

            } else {
                if time.Since(start).Seconds() > 10 {
                    StopStream(PID)
                    StreamRunning = false;
                    start = time.Now()
                } 
            }
        }
    
        time.Sleep(100)
    }
}

func postHTTP(url string, requestString string) ([]byte, error){

    var blankBody []byte 

    payload := strings.NewReader(requestString)

    client := &http.Client{}
    req, clientError := http.NewRequest("POST", url, payload)
    if clientError != nil {
        return blankBody, clientError 
    }
    req.Header.Add("Content-Type", "application/json")

    res, requestError := client.Do(req)
    if requestError != nil {
        return blankBody, requestError
    }

    defer res.Body.Close()
    returnBody, returnError := ioutil.ReadAll(res.Body)

    return returnBody, returnError
}

func StartStream()(string, error) {
    fmt.Println("Start Stream")
    response, StreamOnError := postHTTP("http://localhost:3000/startStream","{\"devicePath\":\"/dev/video0\",\"streamName\":\"LumiPi-003\"}")
    if StreamOnError != nil {
        fmt.Println("Stream On Error: ", StreamOnError.Error())
        return "0", StreamOnError
    }
    splitstrings := strings.Split(string(response),",")
    for i := range splitstrings {
        if strings.Contains(splitstrings[i], "\"pid\":") {
        linesplit := strings.Split(splitstrings[i],":")
        return linesplit[1], nil
        }
    }
    return "0", nil
}

func StopStream(PID string)(error) {
    fmt.Println("Stop Stream")
    command := "{\"pid\":" + PID +  "}"
    _, StreamOnError := postHTTP("http://localhost:3000/stopStream",command)
    if StreamOnError != nil {
        fmt.Println("Stream Off Error: ", StreamOnError.Error())
        return StreamOnError
    }
    return nil 
}

下图显示了 time.sleep 对程序的影响。

在此处输入图像描述

标签: gocpuraspberry-pi4

解决方案


当 rpio.Open() 仍然打开时,time.Sleep() 函数导致 PI 崩溃。

打开、读取引脚和关闭允许 time.Sleep() 以更大的延迟使用,这反过来又降低了 cpu 使用率,因为它不是不断循环。

在此处输入图像描述


import (
    "fmt"
    "github.com/stianeikeland/go-rpio"
    "os"
    "io/ioutil"
    "net/http"
    "strings"
    "time"
)

func main() {

    fmt.Println("Starting Stream Control 0.1")

    var PID string
    start := time.Now()

    StreamRunning := false;

    fmt.Println("Reading and Controlling")
    for {

        pinOpenError := rpio.Open()
        if pinOpenError != nil {
            fmt.Println("Pin Open Error: ", pinOpenError.Error())
            os.Exit(1)
        }

        pin := rpio.Pin(18)
        pin.Input()
        pin.PullUp()
        res := pin.Read()
        rpio.Close()
        if res == 0 {
            if StreamRunning == false  && time.Since(start).Seconds() > 10{
            
            var StartStreamError error
            PID, StartStreamError = StartStream()
            if StartStreamError != nil {
                fmt.Println("Start Stream Error: ", StartStreamError.Error())
            }
            fmt.Println("PID = " + PID)

            start = time.Now()
            StreamRunning = true;

            } else {
                if time.Since(start).Seconds() > 10 {
                    StopStream(PID)
                    StreamRunning = false;
                    start = time.Now()
                } 
            }
        }

    time.Sleep(100*time.Millisecond)

    }
}

func postHTTP(url string, requestString string) ([]byte, error){

    var blankBody []byte 

    payload := strings.NewReader(requestString)

    client := &http.Client{}
    req, clientError := http.NewRequest("POST", url, payload)
    if clientError != nil {
        return blankBody, clientError 
    }
    req.Header.Add("Content-Type", "application/json")

    res, requestError := client.Do(req)
    if requestError != nil {
        return blankBody, requestError
    }

    defer res.Body.Close()
    returnBody, returnError := ioutil.ReadAll(res.Body)

    return returnBody, returnError
}

func StartStream()(string, error) {
    fmt.Println("Start Stream")
    response, StreamOnError := postHTTP("http://localhost:3000/startStream","{\"devicePath\":\"/dev/video0\",\"streamName\":\"LumiPi-003\"}")
    if StreamOnError != nil {
        fmt.Println("Stream On Error: ", StreamOnError.Error())
        return "0", StreamOnError
    }
    splitstrings := strings.Split(string(response),",")
    for i := range splitstrings {
        if strings.Contains(splitstrings[i], "\"pid\":") {
        linesplit := strings.Split(splitstrings[i],":")
        return linesplit[1], nil
        }
    }
    return "0", nil
}

func StopStream(PID string)(error) {
    fmt.Println("Stop Stream")
    command := "{\"pid\":" + PID +  "}"
    _, StreamOnError := postHTTP("http://localhost:3000/stopStream",command)
    if StreamOnError != nil {
        fmt.Println("Stream Off Error: ", StreamOnError.Error())
        return StreamOnError
    }
    return nil 
}

推荐阅读