Подтвердить что ты не робот

В Go, имеет ли смысл писать неблокирующий код?

исходя из node.js точки зрения, где весь код не блокируется.

В Go неблокирование легко достигается с помощью каналов.

Если вы пишете сервер типа node.js в go, имеет ли смысл сделать его неблокирующим? например, при условии, что функция connect() базы данных возвращает канал, по сравнению с блокировкой в ​​ожидании соединения.

для меня это кажется правильным подходом

но...

4b9b3361

Ответ 1

Блокирование и неблокирование не связаны с производительностью, они касаются интерфейса. Если у вас есть один поток выполнения, тогда блокирующий вызов мешает вашей программе выполнять какую-либо полезную работу во время ожидания. Но если у вас несколько потоков выполнения, блокирующий вызов не имеет особого значения, потому что вы можете просто оставить этот поток заблокированным и сделать полезную работу в другой.

В Go, goroutine заменяется на другой, когда он блокирует операции ввода-вывода. Во время выполнения Go использует неблокирующие системные вызовы ввода-вывода, чтобы избежать блокировки потока операционной системы, чтобы на нем мог запускаться другой goroutine, в то время как первый ожидает его ввода/вывода.

Goroutines действительно дешевы, поэтому писать неблокирующий код стиля не требуется.

Ответ 2

Записать функции блокировки. Язык позволяет легко превратить синхронный вызов в асинхронный.

Если вы хотите вызывать функцию асинхронно, используйте оператор go. Что-то вроде этого:

c := make(chan bool)
go func() {
    blockingFunction()
    c <- true
}()

// do some other stuff here while the blocking function runs

// wait for the blocking function to finish if it hasn't already
<-c

Ответ 3

В Go системные вызовы реализуются неблокирующим способом, используя наиболее эффективный базовый механизм, поддерживаемый ОС (например, epoll). Если у вас нет другого кода для запуска, пока вы ждете результата вызова, он блокирует поток (из-за отсутствия лучшего результата), но если у вас есть альтернативные goroutines, они будут выполняться вместо этого.

Обратные вызовы (как вы привыкли использовать в js) допускают, по существу, одну и ту же основную механику, но, возможно, более умную гимнастику, необходимую для программиста.

В Go, ваш код для запуска после вызова функции задается сразу после вызова функции, а не определяется как обратный вызов. Код, который вы хотите запустить параллельно пути выполнения, должен быть завернут в goroutine, с сообщением через каналы.

Ответ 4

Для типичных приложений типа веб-сервера я бы рекомендовал не делать все асинхронным. Есть несколько причин.

  • Легче рассуждать о серийном блоке кода, чем асинхронный код (проще видеть ошибки)

  • Обработка ошибок golang основана на defer(), panic() и recover(), что, вероятно, не даст вам то, что вы хотите, с асинхронным кодом на 100%

  • Goroutines может протекать, если вы не будете осторожны [одно обсуждение]. Чем больше у вас асинхронного поведения, тем сложнее выявить эти проблемы и тем более вероятно, что они появятся.

Одна стратегия - сосредоточить асинхронность на высоком уровне и оставить все остальное блокирующим. Таким образом, у вас может быть "блок-обработчик", который логически отличен от "blob-обработчика запроса". Они оба работают в отдельных goroutines и общаются с использованием каналов. Но внутри "обработчика базы данных" блокируются блокировки подключения к базе данных и выполнения каждого запроса.

Вам не нужно выбирать асинхронный асинхронный или 0% асинхронный.

Ответ 5

Блокирующие интерфейсы всегда проще и лучше, чем неблокирующие. Красота Go заключается в том, что она позволяет вам писать параллельный (и параллельный) код в простой и простой причине, блокируя стиль.

Мода для неблокирующего программирования объясняется недостатками в языках, которые люди используют (особенно JavaScript), а не потому, что неблокирующее программирование по своей сути лучше.