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

Improve executor ergonomics #27

Merged
merged 4 commits into from
Sep 7, 2020
Merged

Conversation

glommer
Copy link
Collaborator

@glommer glommer commented Sep 7, 2020

What does this PR do?
This PR greatly improves the ergonomics of creating and dealing with executors

Motivation
It really sucked before.

Checklist
[x] I have added unit tests to the code I am submitting
[] My unit tests cover both failure and success scenarios
[] If applicable, I have discussed my architecture
[x] The new code I am adding is formatted using rustfmt

Glauber Costa added 4 commits September 6, 2020 20:10
This is an ergonomics effort, so that we can easily know which executor
we are executing on.
Some functions that access the executor are available through Task,
which allow us to access the local executor without having a reference
to it (through its local thread local variable).

However Task's main role is to spawn a new task and store its result.
So it requires a type generic parameter, T.

For helper functions that don't spawn we have to write Task::<()>::
which is a hassle.

This patch adds Local, an alias to Task::<()>::
It is easy to spawn an executor in the current thread: all we have to do is
create it.

However, there are two main problems with it:

 1. The future that we create initially does not live in a task queue. This is
    pretty much a requirement, because the run() function just executes a future
    to completion. There are real problems arising from the fact that this future
    is not on a task queue. For example, we can't call later().await on it (as
    what that does is move ourselves to the back of the task queue).

 2. The potential of a thread-per-core system is only realized when there are
    many executors, one per each CPU. That means that the user now has to create
    thread, keep them alive, create an executor inside each thread, etc. Not fun.

To make this code more ergonomic, we will create the function
LocalExecutor::spawn_new().  It will create a thread and spawn an executor
inside it, making the creation of executors easier.

The future that the caller passed is executed inside a task queue, meaning
every Scipio function will work.  And he future that we actually pass to run,
is the result of draining that task queue.

When the user is done, the function wait_on_executors() can be called to wait
on all the executors created this way at once.

Like so:

LocalExecutor::spawn_new("hello", Some(0), async move {
    function_on_cpu0().await;
});

for i in 1..N {
	LocalExecutor::spawn_new("hello", Some(i), async move {
	    function_on_cpu_aux(i).await;
	});
}

LocalExecutor::wait_on_executors();

The next step in ergonomics for this is having a single entry point
that creates N executors and wait on them. However it is a bit hard
to figure out the details of how this should look like without having
inter-executor channels for communications. So we will defer.
This is already using the newly added ergonomic functions.
@glommer
Copy link
Collaborator Author

glommer commented Sep 7, 2020

Rewrite of history from PR #26

$ git diff glauber/ergonomics..glauber/ergonomics
(empty)

@glommer glommer merged commit 467321e into DataDog:master Sep 7, 2020
@glommer glommer deleted the ergonomics-v2 branch December 21, 2020 16:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant