9

I am building application which will create a lot of threads. Each thread will connect to different remote server, and each thread has to always communicate with it's server.

Before I used PHP, it is bad solution for such goal. My opinion how native threads work: For example we have 100 threads on single core. And the core will split it's working time between all threads.

And here from what I have read and understand:

If I open lot goroutines, one goroutine can block the execution of others goroutines. The execution will be passed to other in specific cases (maybe when current goroutine sleeps or something like that). But it doesn't work like native threads.

I need to make all threads to be executed fluently. Like the same processor's time for each goroutine. I don't need that some goroutine is being executed for long time and other will wait..

Can I achieve it with golang ? Or better use another language (which one) ?

icza
  • 389,944
  • 63
  • 907
  • 827
Mikael
  • 1,209
  • 1
  • 16
  • 47
  • Goroutines are assigned to threads. A goroutine may not yield if it does not perform any i/o or communicate with other goroutines. So if your goroutines are not tight loops, thousands of them can exist without noticeable blocking. – Burak Serdar Feb 26 '20 at 14:40
  • As someone who's done a lot of PHP in the past, and now uses go as a main language, I can tell you based on my experience that golang is a great pick. It's quite quick to learn the syntax, and allows you to write something that works quickly. It's got some more nuanced features that will trip you up at first, but that's to be expected. The bottom line when using concurrency (not parallelism!) for performance will mean you'll have to use `go test -bench` + profile the code to find the sweet-spot. Doing everything in a routine might not be as fast as batching things etc... – Elias Van Ootegem Feb 26 '20 at 15:11
  • 1
    I went to a talk where Dave Cheney ran [this mandelbrot](https://github.com/davecheney/high-performance-go-workshop/tree/master/examples/mandelbrot) example sequentially, then profiled it with a routine per pixel, and finally a routine per row. The latter being the fastest option. You'll probably be able to find the presentation online somewhere, it's a good way to get introduced to the golang toolchain – Elias Van Ootegem Feb 26 '20 at 15:18
  • @EliasVanOotegem, do I understand right, that real parallelism (when several processes or threads being executed in same time) possible only with multi cores? If we have 8 cores - it means only 8 threads may be executed with real parallelism. – Mikael Feb 26 '20 at 15:25
  • @Mikael There is no direct correlation. You may have more threads than cores. See [Number of threads used by Go runtime](https://stackoverflow.com/questions/39245660/number-of-threads-used-by-go-runtime/39246575#39246575). – icza Feb 26 '20 at 15:36
  • @icza, I know it, I meant the real difference between real parallelism and concurrency. Concurrency means that process is always switching between threads or processes ... – Mikael Feb 26 '20 at 15:57
  • a reference for difference between parallelism vs concurrency : https://blog.golang.org/concurrency-is-not-parallelism . `In programming, concurrency is the composition of independently executing processes, while parallelism is the simultaneous execution of (possibly related) computations. Concurrency is about dealing with lots of things at once. Parallelism is about doing lots of things at once.` – Dolanor Feb 26 '20 at 16:46

1 Answers1

26

Concurrency is one of Go's main strengths. This doesn't mean the Go runtime magically solves all issues and cases and makes all your code lightning fast. You can write bad code in any language. But concurrency is built into the language. It hands you several language tools, means to write efficient concurrent code easily, such as goroutines, channels, select statement, synchronization primitives.

A goroutine is a lightweight thread. It costs a lot less than a real OS thread, and multiple goroutines may be multiplexed onto a single OS thread. The spec defines them as "an independent concurrent thread of control within the same address space".

The go runtime is capable of handling thousands or even hundreds of thousands of goroutines without a problem. As an example, the HTTP server in the standard lib handles all incoming requests by launching a new goroutine for each. Yet, it is capable of handling tens of thousands of requests per second for a typical request load (benchmark source).

So all-in-all, just don't write "bad code". The goroutine scheduler is not (fully) preemptive, so make sure your goroutines don't do senseless computation that would prevent the scheduler to run other goroutines. Typically, system calls, IO operators and blocking operations (e.g. sending on / receiving from channels) are good yielding points. Many code do these under the hood even if you don't know it, so most code does not cause a problem. If one of your goroutines must do extensive calculations, you can always call runtime.Gosched() to yield the processor, allowing other goroutines to run.

icza
  • 389,944
  • 63
  • 907
  • 827
  • If the goroutine perform communication with ssh or smtp server, is it i/o operation ? And will it block other goroutines ? – Mikael Feb 26 '20 at 16:32
  • 1
    @Mikael Sending / receiving data on a network connection is IO operation. It doesn't block other goroutines. – icza Feb 26 '20 at 16:34
  • IIRC, Go can use multiple cores (parallelism), so even if one of the goroutines must do extensive calculations, other goroutines can do their job, can't they? (unless the user sets the number of OS threads that manage all the goroutines to be only 1) – starriet May 11 '23 at 23:43