5 ms·
So it is preemptively switching then? > It doesn't really imply anything about how parallel (or not) the fibers execute What's all the fuss about paralllelism
by devxpy 8y ago
So it is preemptively switching then?
> It doesn't really imply anything about how parallel (or not) the fibers execute
What's all the fuss about paralllelism in the article about then?
- rubyn00bie 8y agoNo they aren't preemptively switching/scheduling, you have to schedule it yourself... I could be wicked wrong though, it's been a long while since I futzed with fibers.
- coder543 8y ago> So it is preemptively switching then? Any time you call a blocking function that the system provides, it should immediately yield the fiber, which makes it look preemptive. If you write a loop that just spins forever, that could block the whole system, potentially, making the abstraction leaky. In a language like Ruby, they could definitely add some true preemption, but I don't know if that's what they plan to do. From the article: "Fibers, on the other hand, are semantically similarly to threads (excepting parallelism), but with less overhead." So, the author definitely isn't implying parallelism of the fibers. > What's all the fuss about paralllelism in the article about then? The author was talking about different methods for handling more than one request at a given time, which include forking and threads. With Ruby's GIL, threads are a lot less attractive than they could be. A good fiber implementation can handle tons of network requests concurrently and very efficiently even on a single core, which is the case being discussed here. At the end, the author discusses a hybrid approach of forking and fibers, where each processor core would have a fork of the Ruby program running, and each fork would have its own fiber pool, running many tasks concurrently. In languages that don't have a GIL, forking is rarely a tool that I reach for. It really hurts your database pooling and all sorts of other small problems, but it's a common trade-off when using Ruby, Python, and Node.
- devxpy 8y ago> Any time you call a blocking function that the system provides, it should immediately yield the fiber, which makes it look preemptive. Makes sense. It let's you avoid the quite verbose and incompatible async/await syntax. --- > The author was talking about different methods for handling more than one request at a given time, which include forking and threads I feel like if the author suggests forking, he should also provide a way for reliable robust message passing, like erlang. --- Thanks for such a detailed explanation. I wish more languages supported Erlang style processes. That are green, preemptively switched and multi-core! Do you have any experience writing such systems? I was thinking to experiment with the cpython interpreter.
- pooppaint 8y ago> Any time you call a blocking function that the system provides, it should immediately yield the fiber, which makes it look preemptive. In the old days we would call this cooperative to contrast it from preemptive. This is the essence of cooperative, yielding at explicit points be they IO request, timers, or waiting on a message queue. Preemptive used to mean a certain thing and this is not it at all.
- devxpy 8y agoExactly why they said that it “looks” preemptive. It’s a mirage...
- monocasa 8y agoExcept "preemptive" is literally defined as the contrast of this scheme.
- coder543 8y agocooperative multitasking typically implies (to me, at least) that the programmer is required to explicitly / manually yield their task, which is annoying, error prone, and isn't required here. The system's blocking functions will handle that behind the scenes. Fibers are cooperative here, but not from the programmer's point of view, and that's an important distinction to make. If you write the same code for a cooperative system as you would for a preemptive system, is there really any difference to the programmer? It looks preemptive. If anything, properly implemented cooperative systems are more efficient. Most of the time when people ask the question that is asked higher in the thread, I believe they're worried that they will be responsible for remembering to yield control. I'm pretty sure I did a decent job in my previous comment of explaining that the system only looks preemptive, and that it is possible to block it with some uncooperative code, so I'm not sure what point you're trying to make.
- monocasa 8y agoThat's always how it worked though. In the cooperative multitasking that people complain about (in early Windows and Mac for instance), "blocking I/O" called yield internally, and you only needed to call yield() manually in long running computations that didn't have any I/O. What you're describing is bog standard cooperative multitasking.
- jashmatthews 8y agoForking is going out of fashion in Ruby land really fast due to the problems you mentioned. Now multi-threading is the norm it's easier to just run one process per core and live with a little extra RAM usage. I was working on some more improvements to forked memory usage in CRuby but I don't think it's worth pursuing.
- joelbluminator 8y agoWhat are you basing that it's going out of fashion? Shopify and Github both run unicorn which is pre forking as far as i know. I think some companies prefer to prevent thread safety issues and pay the extra performance cost.
- jashmatthews 8y agoYeah, and Shopify are still using Resqueue too but almost all newer large apps are going multi-threaded from the start and using Puma + Sidekiq. Puma has exceeded Unicorn in total downloads from RubyGems now.
- coder543 8y agoI meant all kinds of internal forking. Running a process per core is just pre-forking.
- jashmatthews 8y agoSidekiq just runs N independent processes in the default setup. No forking at all. Pre-forking is an optional thing in Sidekiq Enterprise.
- coder543 8y agook, so that is a fair distinction. The point I'm trying to make is that you can't share resources easily between all of those processes, even though they're on a single machine, so you usually open a lot more database connections that you would need with a single shared connection pool. So, people often end up dealing with PgBouncer and other inconveniences much earlier than they would otherwise need. But you're right, it's not necessarily forking.
- kabes 8y agoNope, they're coroutines, which are non-preemptive. Similar to generator functions (which is a subset). https://en.wikipedia.org/wiki/Coroutine https://en.wikipedia.org/wiki/Coroutine