Hi, @drpaneas, I didn’t ignore your reply, just been a bit hectic lately!
No experience !
I would be surprised if the creation of a socket creates a real file in the filesystem. Most (if not all) files in the
/proc directories are “virtual” files. Just like how Python takes object-oriented programming to the max and says “everything is an object”, the *nix analogy is that “everything is a file.”
Reading from or writing to these virtual files doesn’t actually touch the disk; the operating system interprets IO to/from these files specially. For example, the command
cat /dev/zero > /dev/null will run forever. It reads data from the
/dev/zero pseudo-device (which always “reads” arrays of bytes whose values are all zero) and dumps it into the
/dev/null pseudo-device (which accepts any writes and just discards the data).
When you create a socket, it’s probably exposed through the VFS as a file, but it’s not an actual file written to the disk, so the bottleneck of writing to the disk doesn’t apply.
Regarding your question about using more than 12 goroutines on a 12-core server, the TL;DR answer is: The number of goroutines you should use is (usually*) not dependent on the number of physical or virtual cores on your server.
I am not intimately familiar with Linux’s (or any OS’s) network drivers/stack, so I don’t know if sockets can be opened in parallel or not, but I want to say that the idea of goroutines is not really about parallelism, it’s about concurrency:
Just like how in C#,
Tasks are not necessarily about parallelism- They’re a way to make efficient use of OS resources (e.g. OS-level threads) by multiplexing multiple tasks on the same OS thread (whenever an operation needs to block, you
await it, which is a way to pass control back to the CLR to schedule another task on the thread), and in Python’s
asyncio module and in Node, there’s an event loop that runs unblocked code and delegates blocking operations to some other resource (sometimes? a thread).
For better or worse, in Go, I use goroutines the same way I use tasks in C# except that you don’t have to worry about CPU- vs. I/O- intensive operations and whether it should run in
Task.Run or not, or if a function is
async vs. synchronous. Those issues go away in Go and the question instead becomes about concurrency: “Does C require B and does B require A or can I do A and B at the same time and I only need the result of both for C?”
* There are times that taking the physical hardware of the computer into account is beneficial: If you’re executing a mathematical operation over a large data set, it might make sense to subdivide that operation into multiple chunks to better utilize your hardware and it might make sense to limit the number of chunks based on the number of (probably physical) cores. In your use case, though, I do not believe you will get significant differences in performance characteristics by increasing or limiting your number of goroutines to your physical or virtual core count.