Как сделать безгражданские связи с гориллой мукс? - PullRequest
0 голосов
/ 15 мая 2018

Моя программа работает нормально с одним подключением за раз, но не с одновременными.

Мне нужно, чтобы все соединения обрабатывались одной функцией, которая будет содержать все данные, которые мне нужны в моем сервисе, и это не работает нормально, поэтому я проиллюстрировал простой код ниже:

package main

import (
    "encoding/json"
    "fmt"
    "github.com/gorilla/mux"
    "github.com/rs/cors"
    "net/http"
    "reflect"
    "time"
)

var Out struct {
        Code     int             `json:"status"`
        Message  []interface{}   `json:"message"`
}

func Clear(v interface{}) {
    p := reflect.ValueOf(v).Elem()
    p.Set(reflect.Zero(p.Type()))
}

func YourHandler(w http.ResponseWriter, r *http.Request) {
    Clear(&Out.Message)
    Out.Code = 0

    // w.Header().Set("Content-Type", "application/json; charset=UTF-8")
    w.Header().Set("Access-Control-Allow-Origin", "*")
    w.Header().Set("Access-Control-Allow-Headers","Content-Type,access-control-allow-origin, access-control-allow-headers")
    w.WriteHeader(http.StatusOK)

    for i:=0; i<10; i++ {
        Out.Code = Out.Code + 1
        Out.Message = append(Out.Message, "Running...")
        time.Sleep(1000 * time.Millisecond)

        if err := json.NewEncoder(w).Encode(Out)
        err != nil {
            http.Error(w, err.Error(), http.StatusInternalServerError)
        }
    }
}

func main() {
    r := mux.NewRouter()
    r.StrictSlash(true);

    r.HandleFunc("/", YourHandler)

    handler := cors.New(cors.Options{
        AllowedOrigins: []string{"*"},
        AllowCredentials: true,
        Debug: true,
        AllowedHeaders: []string{"Content-Type"},
        AllowedMethods: []string{"GET"},
    }).Handler(r)

    fmt.Println("Working in localhost:5000")
    http.ListenAndServe(":5000", handler)
}

Если вы запустите этот код, вы не увидите ничего плохого в одном соединении за раз, но если вы запустите его в другой вкладке / браузере / и т. Д., В то же время из-за задержки код состояния не будет от 1 до 10, но он будет перетасовываться со всеми вызовами.

Так что я предполагаю, что это означает, что это не состояние, и мне нужно, чтобы оно было, поэтому даже при 300 подключениях одновременно он всегда будет возвращать код состояния от 1 до 10 в каждом.

Как я могу это сделать? (Как я уже сказал, это простой код, структура и функции рендеринга находятся в отдельных пакетах друг от друга и всего сбора данных и)

Ответы [ 3 ]

0 голосов
/ 16 мая 2018

Gorilla Mix использует net / http-сервер Go для обработки ваших http-запросов.Go создает подпрограмму Go для обслуживания каждого из этих входящих запросов.Если я правильно понимаю ваш вопрос, вы ожидаете, что ответы Go будут иметь ваши собственные коды состояния в порядке от 1 до 10, поскольку вы ожидали, что каждый запрос поступает синхронно в этом порядке.Параллелизм подпрограммы Go не гарантирует порядок выполнения, как потоки Java, если вы знакомы с Java.Таким образом, если подпрограммы Go были созданы для каждого из запросов, созданных в цикле for 1-to-10, тогда подпрограммы будут выполняться самостоятельно, без учета порядка, который идет и завершается первым.Каждая из этих подпрограмм Go будет обслуживать ваши запросы по завершении.Если вы хотите контролировать порядок обработки этих запросов параллельно, но по порядку, вы можете использовать каналы.Посмотрите эту ссылку, чтобы контролировать синхронизацию между вашими 10 Go-подпрограммами для каждого из этих http-запросов.https://gobyexample.com/channel-synchronization

0 голосов
/ 16 мая 2018

Во-первых, я хотел бы поблагодарить ThunderCat и Рамиля за помощь, ваши ответы дали мне север, чтобы найти правильный ответ.

Короткий ответ таков: у меня нет связей без состояния, поэтому я могуне делайте то, что я искал.

Как только это сказал, причина, по которой я думаю (на основе RFC 7230), что это не так, заключается в том, что:

  • В традиционномВ приложении веб-сервера у нас есть программа, которая обрабатывает соединения (Apache, nginx и т. д.) и открывает поток для маршрутизируемого приложения, в то время как в Go мы оба работаем в одном приложении, поэтому все глобальное всегда распределяется между соединениями.
  • В языках, которые могут работать как Go (приложение, которое открывает порт и продолжает его слушать), например C ++, они ориентированы на объекты, поэтому даже общедоступные переменные находятся внутри класса, поэтому вы не будете делиться им, так как вам придетсякаждый раз создавайте экземпляр класса.

Создание потока решит проблему, но у Go его нет, вместо этого у него есть Goroutines, более подробнооб этом в:

https://translate.google.com/translate?sl=ko&tl=en&u=https%3A%2F%2Ftech.ssut.me%2F2017%2F08%2F20%2Fgoroutine-vs-threads%2F

Через несколько дней после этого и помощи здесь я исправлю это, изменив мою структуру на type и поместив ее локально, вот так:

package main

import (
    "encoding/json"
    "fmt"
    "github.com/gorilla/mux"
    "github.com/rs/cors"
    "net/http"
    "reflect"
    "time"
)

type Out struct {
    Code     int             `json:"status"`
    Message  []interface{}   `json:"message"`
}

func Clear(v interface{}) {
    p := reflect.ValueOf(v).Elem()
    p.Set(reflect.Zero(p.Type()))
}

func YourHandler(w http.ResponseWriter, r *http.Request) {
    localOut := Out{0,nil}

    // w.Header().Set("Content-Type", "application/json; charset=UTF-8")
    w.Header().Set("Access-Control-Allow-Origin", "*")
    w.Header().Set("Access-Control-Allow-Headers","Content-Type,access-control-allow-origin, access-control-allow-headers")
    w.WriteHeader(http.StatusOK)

    for i:=0; i<10; i++ {
        localOut.Code = localOut.Code + 1
        localOut.Message = append(localOut.Message, "Running...")
        time.Sleep(1000 * time.Millisecond)

        if err := json.NewEncoder(w).Encode(localOut)
        err != nil {
            http.Error(w, err.Error(), http.StatusInternalServerError)
        }
    }
}

func main() {
    r := mux.NewRouter()
    r.StrictSlash(true);

    r.HandleFunc("/", YourHandler)

    handler := cors.New(cors.Options{
        AllowedOrigins: []string{"*"},
        AllowCredentials: true,
        Debug: true,
        AllowedHeaders: []string{"X-Session-Token","Content-Type"},
        AllowedMethods: []string{"GET","POST","PUT","DELETE"},
    }).Handler(r)

    fmt.Println("Working in localhost:5000")
    http.ListenAndServe(":5000", handler)
}

Конечно, это займет несколько недель, поэтому сейчас я поставил свое приложение за nginx, и теперь оно работает как положено.

0 голосов
/ 15 мая 2018

Обработчики вызываются одновременно сервером net / http . Сервер создает подпрограмму для каждого клиентского соединения и вызывает обработчики для этих подпрограмм.

Gorilla Mux пассивен в отношении параллелизма. Мультиплексор обращается к зарегистрированному обработчику приложения в любом порядке вызова мультиплексора.

Используйте sync.Mutex , чтобы ограничить выполнение одной программой за раз:

var mu sync.Mutex

func YourHandler(w http.ResponseWriter, r *http.Request) {
    mu.Lock()
    defer mu.Unlock()

    Clear(&Out.Message)
    Out.Code = 0
    ...

Это не хорошее решение, учитывая вызовы time.Sleep в обработчике. Сервер будет обрабатывать не более одного запроса каждые 10 секунд.

Лучшее решение - объявить Out как локальную переменную внутри функции-обработчика. С этим изменением, нет необходимости для мьютекса или для очистки:

func YourHandler(w http.ResponseWriter, r *http.Request) {

    var Out struct {
        Code     int             `json:"status"`
        Message  []interface{}   `json:"message"`
    }


    // w.Header().Set("Content-Type", "application/json; charset=UTF-8")
    w.Header().Set("Access-Control-Allow-Origin", "*")
    ...

Если невозможно переместить объявление Out, скопируйте значение в локальную переменную:

func YourHandler(w http.ResponseWriter, r *http.Request) {
    Out := Out // local Out is copy of package-level Out
    Clear(&Out.Message)
    Out.Code = 0
    ...
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...