Skip to content
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

what world should Tasks run in? #35690

Closed
JeffBezanson opened this issue May 1, 2020 · 7 comments · Fixed by #41449
Closed

what world should Tasks run in? #35690

JeffBezanson opened this issue May 1, 2020 · 7 comments · Fixed by #41449
Labels
compiler:inference Type inference minor change Marginal behavior change acceptable for a minor release multithreading Base.Threads and related functionality

Comments

@JeffBezanson
Copy link
Member

Currently, we start Task execution in the newest world, like invokelatest. However, we might instead want them to capture the world they were created in. That would potentially enable us to infer the result of fetch(@spawn ...).

@JeffBezanson JeffBezanson added multithreading Base.Threads and related functionality compiler:inference Type inference labels May 1, 2020
@tkf
Copy link
Member

tkf commented May 5, 2020

capture the world they were created in

Would it make task-local logger inferrable? cc @c42f

@c42f
Copy link
Member

c42f commented May 5, 2020

Oh really good question. I think the answer is no: even regardless of task spawning, dynamically scoped loggers currently can't be inferred at the use site. If we did want them to be fully inferred that's similar to passing them via contextual dispatch and has somewhat similar tradeoffs: extremely good runtime performance, but a lot more recompilation.

I think there's a middle ground between no specialization and full contextual dispatch... something like "taking dynamically scoped variables seriously": the error handling and logging cases have a similar structure where you may want to pass the context down a deep call stack without specializing the intermediate frames. But then specialize any leaf function calls which actually make use of the dynamic context. Anyway, this is quite different from what Jeff is proposing here.

Regarding the world age of Tasks, I'm definitely in favor of having it inherited from the parent Task. This seems like the correct dynamically scoped behavior that we use everywhere else for world age and is also very natural from a structured concurrency point of view.

@tkf
Copy link
Member

tkf commented Jul 8, 2020

However, we might instead want them to capture the world they were created in.

Another advantage with this approach is that this lets the chain/tree of calls started from Base.invoke_in_world to use a consistent world age even in child tasks.

Demo (from #35844 (comment)):

foo() = "First implementation of foo"
function bar()
    Base.invoke_in_world(_entry_point_world, foo)
end

afoo() = fetch(@async foo())
function abar()
    Base.invoke_in_world(_entry_point_world, afoo)
end

# Note `@async` creates a closure so the counter has to be fetched after that.
_entry_point_world = Base.get_world_counter()

@show bar()
@show abar()

println("Now, revise foo:")
foo() = "Second implementation of foo"

@show bar()
@show abar()

prints

bar() = "First implementation of foo"
abar() = "First implementation of foo"
Now, revise foo:
bar() = "First implementation of foo"
abar() = "Second implementation of foo"

Ideally, the last abar() should still return "First implementation of foo".

@StefanKarpinski
Copy link
Member

This seems like a pretty compelling “minor change” ie technically breaking but probably undisruptive enough to be done in a minor release.

@tkf
Copy link
Member

tkf commented Aug 26, 2020

That would potentially enable us to infer the result of fetch(@spawn ...).

Here is my very hacky POC for inferable fetch(task): https://github.com/tkf/InferableTasks.jl/blob/master/src/InferableTasks.jl

Discussion: https://discourse.julialang.org/t/can-we-have-inferable-fetch-task/45541

@c42f
Copy link
Member

c42f commented Oct 7, 2020

How should we initialize the world age for a task? It's really easy to initialize from the parent ptls->world_age in jl_new_task, but this seems to have fairly loose semantics.

In particular, it would be insufficient to make fetch(some_task) inferrable, as some_task could be created in an unrelated context and passed into the current task.

Instead it seems we'd need a composite @fetch_spawn(...), which guarantees that the task which is fetch()ed from was created in the local context.

@jtrakk
Copy link

jtrakk commented Apr 19, 2021

This kind of issue makes me wonder if world-age could be more like a partial order or lattice rather than an integer. The parent task defines f() = 0, then split and Task 1 defines f() = 1 while Task 2 defines f() = 2. Both children have higher age than the parent task but neither child is older than the other (they are twins).

@JeffBezanson JeffBezanson added the minor change Marginal behavior change acceptable for a minor release label Jun 23, 2021
vtjnash added a commit that referenced this issue Jul 2, 2021
N.B. This means serialized tasks will discard this stateful information
and pick up new/different information.

Closes #35690
Closes #41332
vtjnash added a commit that referenced this issue Jul 2, 2021
N.B. This means serialized tasks will discard this stateful information
and pick up new/different information.

Closes #35690
Closes #41332
vtjnash added a commit that referenced this issue Jul 13, 2021
N.B. This means serialized tasks will discard this stateful information
and pick up new/different information.

Closes #35690
Closes #41332
vtjnash added a commit that referenced this issue Sep 15, 2021
N.B. This means serialized tasks will discard this stateful information
and pick up new/different information.

Closes #35690
Closes #41332
KristofferC pushed a commit that referenced this issue Sep 28, 2021
N.B. This means serialized tasks will discard this stateful information
and pick up new/different information.

Closes #35690
Closes #41332
LilithHafner pushed a commit to LilithHafner/julia that referenced this issue Feb 22, 2022
N.B. This means serialized tasks will discard this stateful information
and pick up new/different information.

Closes JuliaLang#35690
Closes JuliaLang#41332
LilithHafner pushed a commit to LilithHafner/julia that referenced this issue Mar 8, 2022
N.B. This means serialized tasks will discard this stateful information
and pick up new/different information.

Closes JuliaLang#35690
Closes JuliaLang#41332
Keno pushed a commit that referenced this issue Jun 5, 2024
N.B. This means serialized tasks will discard this stateful information
and pick up new/different information.

Closes #35690
Closes #41332
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
compiler:inference Type inference minor change Marginal behavior change acceptable for a minor release multithreading Base.Threads and related functionality
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants