-
Notifications
You must be signed in to change notification settings - Fork 17.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
net: add mechanism to wait for readability on a TCPConn #15735
Comments
/cc @ianlancetaylor @rsc |
CL https://golang.org/cl/23227 mentions this issue. |
Updates #15735 Change-Id: I42ab2345443bbaeaf935d683460fc2c941b7679c Reviewed-on: https://go-review.googlesource.com/23227 Reviewed-by: Ian Lance Taylor <[email protected]>
Updates #15735. Fixes #15741. Change-Id: Ic4ad7e948e8c3ab5feffef89d7a37417f82722a1 Reviewed-on: https://go-review.googlesource.com/23199 Run-TryBot: Mikio Hara <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Brad Fitzpatrick <[email protected]>
read(2) with a count of zero may be used to detect errors. Linux man page confirms, as does POSIX's read(3p) here. Mentioning it in case it influences this subverting of a Read(0 bytes) not calling syscall.Read. |
I found a way to do without this in net/http, so punting to Go 1.9. |
Actually, the more I think about this, I don't even want my idle HTTP/RPC goroutines to stick around blocked in a read call. In addition to the array memory backed by the slice given to What I'd really like is a way to register a My new proposal is more like: package net
// OnReadable runs f in a new goroutine when c is readable;
// that is, when a call to c.Read will not block.
func (c *TCPConn) OnReadable(f func()) {
// ...
} Yes, maybe this is getting dangerously into event-based programming land. Or maybe just the name (" I would use this in http, http2, and grpc. /cc @ianlancetaylor @rsc |
Sounds like you are getting close to #15021. I'm worried that the existence of such a method will encourage people to start writing their code as callbacks rather than as straightforward goroutines. |
Yeah. I'm conflicted. I see the benefits and the opportunity for overuse. |
If we do OnReadable(f func()), won't we need to fork half of standard library for async style? Compress, io, tls, etc readers all assume blocking style and require a blocked goroutine. |
Re 0-sized reads. |
@dvyukov, no, we would only use |
This looks like a half-measure. An http connection can halt in the middle of request... |
@dvyukov, but not commonly. This would be an optimization for the common case. |
An alternative interface can be to register a channel that will receive readiness notifications. The other camp wants this for packet-processing servers, and there starting a goroutine for every packet will be too expensive. However, if at the end you want a goroutine, then the channel will introduce unnecessary overhead. |
We need to make sure that this works with Windows IOCP as well. |
Not obvious to me why the API has to handle writes. The thing about reads is that until the data is ready for reading, you can use the memory for other work. If you're waiting to write data, that memory is not reusable (otherwise you'd lose the data you are waiting to write). |
@rsc If we do just 0-sized reads, then write support is not necessary. However, if we do Brad's "My new proposal is more like": |
If memory usage is the concern, it is possible to make long parked G use less memory instead of changing programming style? One main selling point of Go to me is high efficiency network servers without resorting to callbacks. Something like shrink the stack or move the stack to heap by the GC using some heuristics, that will be littile different from spinning up a new goroutine on callback memory usage wise, and scheduling wise a callback is not much different than For the backing array, if it is preallocated buffer, than a callback doesn't make much different than Edit: |
How about a epoll like interface for type PollableListener interface {
net.Listener
// Poll will block till at least one connection been ready for read or write
// reads and writes are special net.Conn that will not block on EAGAIN
Poll() (reads []net.Conn, writes []net.Conn)
} Then the caller of Note that this only needs to be implemented in the runtime for those Listeners that multiplexed in the kernel, like the Edit: type IOReadyNotify func(mode int32) And we store this in the |
I'm fairly new to Go but seeing the callback interface is a little grating given the blocking API exposed everywhere else. Why not expose a public API to the netpoll interfaces? Go provides no standard public facing event loop (correct me if I'm wrong please). I have need to wait for readability on external FFI socket(s) (given through cgo). It would be nice to re-use the existing netpoll abstraction to also spawn FFI sockets onto rather than having to wrap epoll/IOCP/select. Also I'm guessing wrapping (e.g) epoll from the sys package does not integrate with the scheduler which would also be a bummer. |
For a number of my use cases, something like this :
.. would be nice because I can select on it. I have no idea whether it's practical to implement this though. Another alternative (for some of my cases at least) might be somehow enabling reads to be canceled by using a context. |
@ivanjaros As we know, golang can't get the same performance as c/cpp/rust in most scenarios, but can get near to c/cpp/rust in some scenarios such as IO, and the most important is: goroutine and chan make us write code easier. |
@ivanjaros Standard Go is quite performant, just take a look at fasthttp. It is built using standard Go. The only problem with Go is the amount of sync mechanisms that it requires. That's why I said that a pro-actor pattern might be faster for TLS & HTTP/2. Or any protocol that uses streams instead of one single stateless connection. |
@lesismal So it depends on how your Go program is structured. If it has locks, it doesn't. If uses channels, etc... In my benchmarks I had no locks, just plain HTTP (no TLS) with some caching system in both fasthttp & boost::beast. I wouldn't say that Go is less performant than C++ and Rust. It also depends on the library that you use. boost::beast is ok, it does scale well, but it is not as latency sensitive as you might think (truth is that you can easily plug in solarflare's onload in boost::asio and get a performance improvement), and Rust is not as different from Go. They also use coroutines and they also need to lock in some scenarios but they have the advantage of not having a GC ("advantage"). Bechmarks are mostly a lie. People prepare their programs for the benchmark in question (like gnet's case). Production ready environments don't need to lie in their benchmarks (fasthttp) |
@d2gr
|
@lesismal |
you are mixing apples and oranges here. nobody is talking about http servers here. gnet is merely networking framework(like ALL the projects mentioned before). what you build on top of it is up to you. |
@d2gr @ivanjaros Please refer to the reasons I've mentioned here and in previous comments. Here are some benchmark reports, you can run the test in your own env: |
@lesismal, @ivanjaros, @d2gr: it isn't clear to me how the above discussion relates to the feature proposed in this issue. For off-topic performance discussions, please start a thread on the |
@bcmills Sorry for spamming a bit, but my comments where related to the issue. At least this one #15735 (comment) |
@bcmills My previous related comments:
|
@bcmills Also that's why I hope if you add |
just add those functions to net.Conn:
|
@AnimusPEXUS Thanks, but that doesn't address this issue. This issue is about putting a goroutine to sleep until there is something to read. |
@ianlancetaylor determining "if ther's something to read" is system-to-system specific question. for NIX* it's 'select' function. maximum you can do here for nix is make callback or push signal after select returned and if we want select non-blocking, then we have to put socket into non-blocking state. for non-socket/non-unix there only two options: endless loop, constantly checking readiness, or, again, callback if peer can somehow separately indicate 'I have something to read' |
I don’t think Go as it stands today is the best choice for this kind of code. Optimized Rust and C++ servers use a combination of compiler-generated state machines ( |
@AnimusPEXUS There is a reason that this issue is still open. |
EDIT: this proposal has shifted. See #15735 (comment) below.
Old:
The net/http package needs a way to wait for readability on a TCPConn without actually reading from it. (See #15224)
http://golang.org/cl/22031 added such a mechanism, making Read(0 bytes) do a wait for readability, followed by returning (0, nil). But maybe that is strange. Windows already works like that, though. (See new tests in that CL)
Reconsider this for Go 1.8.
Maybe we could add a new method to TCPConn instead, like WaitRead.
The text was updated successfully, but these errors were encountered: