在gorilla/mux框架中使用Go协程(Go routines)

huangapple go评论67阅读模式
英文:

Using Go routines in gorilla/mux framework

问题

我们正在使用gorilla mux框架来处理Web请求,我认为它会自动在所有CPU核心上运行。在这种情况下,对于CPU密集型进程(例如循环遍历大型对象),使用Go协程是否有好处呢?

英文:

We are using gorilla mux framework for handling web requests which I suppose automatically runs on all the cpu cores. Is there a benefit of using go routines in such a case for cpu intensive processes for eg looping through a large object?

答案1

得分: 11

我假设自动运行在所有的CPU核心上。

你的假设是错误的,有点误解。

从Go 1.5开始,Go会利用所有的核心,通过在不同的核心上运行Go协程来实现。但是如果你不使用Go协程,它就无法利用这一点。

在这种情况下,对于CPU密集型的处理,比如遍历一个大对象,使用Go协程可能会有好处。但是你问错了问题。

你使用Go协程的主要目的不是为了利用不同的CPU核心(尽管这也可能是一个好处)。你使用Go协程是为了在执行需要一段时间的操作时,保持程序不被阻塞。

在Web应用程序的情况下,大多数请求通常都不是CPU密集型的。但是它们通常会花费很多时间(从计算机的角度来看)等待事情发生。它们等待请求主机名的DNS查找,等待数据库查找用户凭据以建立会话,等待数据库存储或返回行以生成HTTP响应等等。

如果没有Go协程,在执行这些操作时,你的服务器将无法做任何其他事情。所以如果你的典型HTTP请求需要1秒钟来查找DNS,验证授权cookie,从数据库中查找结果,并发送响应,那么没有其他HTTP客户端可以同时被服务。

幸运的是,http包,它被Gorilla(以及几乎所有其他Go的Web框架)使用,已经使用Go协程来处理请求。所以你已经在每个HTTP请求中使用(至少)一个Go协程。

是否使用额外的Go协程更多地取决于你的应用程序设计,而不是“使用更多的CPU核心”。

一些建议:

  1. 如果你在为一个请求执行多个可以并行完成的任务,可以使用Go协程。假设你需要执行3个数据库查询,你可以在每个Go协程中执行一个查询,这样它们可以同时运行。它们可能在不同的CPU核心上运行,但这与实际性能无关,因为每个查询实际上什么都不做,只是在等待数据库。但你仍然可以提高性能。(为了完整起见,我要提到,Go协程不是并行运行数据库查询的唯一方式,但它们是Go的惯用方式,也是Go中简单的方式)。
  2. 如果你有在HTTP请求中运行的任务,但不影响HTTP响应,你可以在一个Go协程中运行它们,这样你的响应可以更快地返回。日志记录是一个常见的例子。你可能想要记录你的HTTP请求,但如果日志记录器很慢,你可能不想在发送HTTP响应之前等待日志记录完成。所以在一个Go协程中完成它。日志记录器可以慢慢地完成,而在客户端已经收到响应之后。另一个例子是发送电子邮件,请不要在响应HTTP客户端之前等待电子邮件发送完成。
英文:

> I suppose automatically runs on all the cpu cores.

You suppose wrong. Sort of.

As of Go 1.5, Go will use all of your cores, by running go routines on different cores. But if you don't use go routines, there's no way for it to take advantage of this.

> Is there a benefit of using go routines in such a case for cpu intensive processes for eg looping through a large object?

There can be. But you're asking the wrong question.

You don't use Go routines primarily to take advantage of different CPU cores (although this can also be a benefit). You use Go routines to keep your program from blocking while doing something that takes a while.

In the case of a web application, most requests are usually not CPU intensive at all. But they usually spend a lot of time (in computer terms) waiting around for things to happen. They wait for DNS lookups on the request hostname, they wait for the database to look up user credentials to establish a session, they wait for the database to store or return rows to produce the HTTP response, etc.

Without go routines, while doing these things, your server would be unable to do anything else. So if your typical HTTP request took, say, 1 second, to look up DNS, validate an authorization cookie, look up results from a database, and send a response, no other HTTP client could be served simultaneously.

Fortunately, the http package, which is used by Gorilla (and practically every other web framework for Go) already uses Go routines to handle requests. So you're already using (at least) one Go routine per HTTP request.

Whether it makes sense to use additional go routines is more up to your application design than "using more CPU cores."

Some suggestions:

  1. If you're doing multiple things to serve a request that could be done in parallel, use go routines. Suppose you need to do 3 DB queries, you can do each one in a Go routine, so they run simultaneously. They may run on different CPU cores, but that's completely irrelevant to actual performance, since each one is essentially doing nothing, and just waiting for the database. But you'll still improve performance. (For completeness sake,I'll mention that goroutines aren't the only way to run database queries in parallel--but they are the idiomatic Go way, and the easy way in Go).
  2. If you have tasks that are run by an HTTP request, but don't affect the HTTP response, you can run them in a Go routine, so your response can return sooner. Logging is a common example. You probably want to log your HTTP requests, but if the logger is slow, you probably don't want to wait for logging to finish before sending your HTTP response. So do it in a go routine. The logger can take it's sweet time and finish after the client has already received their response. Another example is sending emails--please don't wait for an email to be sent before responding to an HTTP client.

huangapple
  • 本文由 发表于 2017年3月20日 14:46:44
  • 转载请务必保留本文链接:https://go.coder-hub.com/42897351.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定