-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
Multithreading #8112
Multithreading #8112
Conversation
Move event_loop ivars to Thread Use libevent pthread support
…. Added main thread as a worker.
…ed. It now supports MT for send/receive and select operations.
…lation is fixed). Use simpler but effective RR scheduling instead.
… select statement
…nqueue_self as Scheduler#enqueue now always sends the fiber to the local queue.
…dcoded value (otherwise the constructor of Time requires the value of UNIX_EPOCH already set to validate the parameters)
Only positive integer values are accepted or empty string (that switches back to the default number of workers). Any other value will make the program to crash.
… and enable it only in multithread mode
private def self.event_base | ||
Thread.current.event_base | ||
end | ||
|
||
private def self.loop_fiber |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not used anywhere.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm... that's not true. It's used in many places.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't found it in this PR nor with grep -rn
in master.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm talking about this very private class method, not the instance method and variable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The instance variable belongs to Thread
. This static method is defined in Crystal::EventLoop
module.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, but sorry I didn't undestand the code URL you mentioned, where EventLoop.loop_fiber
is used then?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same file, line 26
crystal/src/crystal/event_loop.cr
Line 26 in 6c6cadd
loop_fiber.resume |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh ok sorry, thanks. I didn't know this language feature, to call a static method like that.
module Crystal::EventLoop | ||
{% unless flag?(:preview_mt) %} | ||
def self.after_fork | ||
Thread.current.event_base.reinit |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thread.current.event_base.reinit | |
event_base.reinit |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks fantastic! I'm excited about how much thought has been given to making it easy on application developers to get parallel execution while mitigating thread-safety issues!
@@ -58,8 +58,11 @@ end | |||
# | |||
# 2.times { ch.receive } | |||
# ``` | |||
def spawn(*, name : String? = nil, &block) | |||
def spawn(*, name : String? = nil, same_thread = false, &block) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Such a small thing but sooooo crucial. I use spawn
all the time to move work out-of-band but I rely on it waiting until the current fiber is yielded.
Something that's been in the back of my mind every time I've done it is "this isn't going to work when Crystal goes multithreaded" but this one argument, along with fibers staying within their threads, solves that problem! 💯 🙌🏼
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just make sure nobody changes the contract from "stays on the same thread" to "is initially queued for the same thread" in case job stealing is implemented :D
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jgaskins I would recommend using Channel to wait for the result. The same_thread
is more to ensure the execution context than the scheduling.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just notice that same_thread
should be typed as Bool
here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@j8r Type restrictions are optional in Crystal. In this way one can pass a nilable thing and it will work. Restricting it to Bool
will make it less flexible, forcing you to do things like !!exp
.
I think we should embrace the way Crystal lets you omit type annotations. If something is not strictly required by the language then we shouldn't always push for it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a big PR that adds initial and experimental support for multithreading. It works side by side with the current single thread implementation and must be enabled with the
preview_mt
flag.There is an upcoming blog post explaining details about the implementation and decisions made on this work.
Things covered by this PR:
Channel
: re-created from scratch because with the previous implementation it was harder to make a multi threadselect
operation.Mutex
Things not covered by this PR:
Array
is not thread safe and must be protected by a mutex in case it's shared between fibers