Обновление значения в горутине - PullRequest
0 голосов
/ 07 мая 2020

В настоящее время я работаю над личным проектом по изучению Golang, но у меня возникают некоторые проблемы, когда я начинаю работать над Goroutines, я думаю, что есть некоторые концепции, которые я неправильно понимаю. Короче говоря, в моем коде есть структура с функцией приемника «l oop», которая выполняет процесс каждые 10 секунд в бесконечном l oop, пока программа не завершится, она уже работает. Теперь я хочу добавить простой веб-сервер, с которого мне нужно иметь возможность обновлять некоторые данные внутри структуры во время работы l oop, вот абстракция проблемы, которую я использую для проверки случая:

package main

import (
    "fmt"
    "net/http"

    "../thing"
)

var Thing1 thing.Thing

func main() {
    Thing1 := thing.NewThing("thing1")
    //This is the loop that is always running
    go Thing1.Loop()
    http.HandleFunc("/", HelloServer)
    http.ListenAndServe(":8080", nil)
}

func HelloServer(w http.ResponseWriter, r *http.Request) {
    if r.URL.Path != "/" {
        http.Error(w, "404 Not found", http.StatusNotFound)
        return
    }
    switch r.Method {
    case "GET":
        http.ServeFile(w, r, "index.html")
    case "POST":
        if err := r.ParseForm(); err != nil {
            fmt.Fprintf(w, "There was an error with the form: %v", err)
            return
        }
        fmt.Println("In handler: " + r.FormValue("fData"))
        Thing1.UpdateData(r.FormValue("fData"))
        http.ServeFile(w, r, "index.html")
    default:
        http.Error(w, "405 Method not allowed", http.StatusMethodNotAllowed)
    }

}
package thing

import (
    "fmt"
    "time"
)

type Thing struct {
    ID   string
    data string
}

func NewThing(id string) Thing {
    return Thing{ID: id}
}

func (t *Thing) Loop() {
    for {
        now := time.Now().Format("15:04:05")
        fmt.Println(t.ID + " starts at " + now)
        fmt.Println(t.ID + " Data: " + t.data)
        time.Sleep(time.Second * 10)
    }
}

func (t *Thing) UpdateData(g string) {
    t.data = g
}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>Test</title>
</head>
<body>
    <p>Test control panel</p>
    <form method="POST" action="/">
        <label>Data</label><input type="text" name="fData" value="">
        <input type="submit" value="submit">
    </form>
</body>
</html>

В основном, когда я нажимаю sh кнопку отправки, я хочу обновить переменную «данные» в структуре Things1, и это должно быть отражено при печати переменной данных внутри l oop, но это не работает, переменная данных всегда печатается как пустая. Я не знаю, что делаю не так, но мне кажется, что мне не хватает фундаментальной концепции горутин. Мы будем благодарны за любые советы.

1 Ответ

2 голосов
/ 07 мая 2020

В вашем main вы начинаете с:

Thing1 := thing.NewThing("thing1")

Это определяет новую локальную переменную с именем Thing1, как если бы вы написали:

var Thing1 Thing

, а затем устанавливает для переменной результат thing.NewThing:

Thing1 = thing.NewThing("thing1")

Между тем ваша функция HelloServer не определяет никаких новых переменных с именем Thing1, но использует внешний (пакет) scope Thing1 - другой экземпляр структуры с ID = "" (пустая строка) и data = "". Когда вы вызываете Thing1.UpdateData(r.FormValue("fData")), адрес этого пустого Thing1 передается в функцию-получатель UpdateData. Этот безымянный объект Thing1 обновляет свои данные, в то время как ваш l oop использует Thing1 с идентификатором "thing1".

Это достаточно легко исправить: просто не создавайте новый Thing1 в главном. Однако, как JimB отметил в комментарии , вы также не синхронизируете обновление данных с доступом к данным. Если вы собираетесь общаться с помощью совместного использования, вам понадобится какая-то блокировка.

(Go поощряет совместное использование путем общения, а не общения путем обмена. Для этого требуется другой способ хотя думает.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...