-
Notifications
You must be signed in to change notification settings - Fork 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
Make Shell::Create
not blocking platform thread by asynchronously setup shell subsystems
#19641
Make Shell::Create
not blocking platform thread by asynchronously setup shell subsystems
#19641
Conversation
…etup shell subsystems.
It looks like this pull request may not have tests. Please make sure to add tests before merging. If you need an exemption to this rule, contact Hixie on the #hackers channel in Chat. Reviewers: Read the Tree Hygiene page and make sure this patch meets those guidelines before LGTMing. |
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 idea looks very interesting to me. From users' perspective, this PR is great as it brings async setup to them in a completely transparent way and there's no extra work for them to receive the benefit. On the other hand, I'm a little concerned by how many pieces of code like https://github.com/scutlight/engine/blob/b791479e926f75c883c0d93251fe780acf69e30f/shell/common/shell.cc#L660-L671 need to be injected not just now, but also for every new API added to Shell
in the future.
@gaaclarke @chinmaygarde @jason-simmons : what's your thought on this? Shall we give Shell
users some extra work if they want async setup so we can leave most Shell
functions intact (#18047), or shall we give no extra work to Shell
users but modify most Shell
functions for async support (this PR)?
@@ -61,16 +61,18 @@ std::unique_ptr<Shell> Shell::CreateShellOnPlatformThread( | |||
std::promise<fml::WeakPtr<SnapshotDelegate>> snapshot_delegate_promise; |
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.
If we're going to land this, Shell::CreateShellOnPlatformThread
should be properly documented by stating that the Shell
returned may not be ready yet due to asynchronous setup but all functions can be called as normal because we'll defer them in a queue until the shell is set up.
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 thing, only if we've reach agreement on this asynchronous setup idea. And there are many failed test cases to be updated due to asynchronous setup.
// creation and then setup the shell. | ||
auto result = std::async( | ||
std::launch::async, | ||
[shell = shell.get(), platform_view = std::move(platform_view), |
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.
Sending a raw pointer shell
to an async operation is not going to cut it. You'll need a shared_ptr.
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 not quite sure whether I've caught you. What's the meaning of 'cut it'? Do you mean that shell
might have been destructed while executing the async operation? In that case, shall I use shell = shell->weak_factory_.GetWeakPtr()
instead?
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.
Sorry, "not going to cut it" is an english idiom that means "isn't going to be adequate".
Yes, the shell could be deleted before this operation or during this operation. A weak pointer isn't going to be good enough. In the case they are happening at the same time you'd need to block the deleting thread until this has completed. The easiest solution is using a shared_ptr.
@@ -391,6 +391,8 @@ class Shell final : public PlatformView::Delegate, | |||
> | |||
service_protocol_handlers_; | |||
bool is_setup_ = false; | |||
std::future<bool> async_waiting_subsystems_; | |||
std::queue<std::future<void>> pending_tasks_before_setup_; |
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.
You are editing and reading this queue from multiple threads, but it's not a threadsafe datastructure.
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.
pending_tasks_before_setup_
is only access on platform thread, it does not need to be thread safe.
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 read through the code and I think you are right. It would be nice to enforce this.
I think there is some promise in this approach since it is taking advantage of the async design of This particular implementation, as it is today, is perilous. I've added some comments on how to make it safe. |
@liyuqian @gaaclarke : Thanks for your reviews. This pr really brings some extra maintain works to |
An inspiration rushed into my mind when I woke up at midnight 🤪 . |
@scutlight : I guess this is going to be replaced by #20142? |
Description
As the related issue refer, the application may be doing too much work on its main thread even in a simple hello_world demo.
That is because the creation of engine on the UI thread takes a noticeable time, and it is blocking the main thread in order to run
Shell::Setup
synchronously.This PR breaks the main thread blocking, by introducing
std::async
to wait for the shell subsystems creation in a background thread.Shell::Setup
will be executed when the subsystems are ready. Before shell is setup, calls to shell subsystem will be pushed into a pending tasks queue which would be run in sequence once the setup is done.Code changes are mainly inside
Shell::CreateShellOnPlatformThread
andShell::Setup
.Related Issues
flutter/flutter#40563 could be resolved by this PR.
Tests
I added the following tests:
Replace this with a list of the tests that you added as part of this PR. A
change in behaviour with no test covering it will likely get reverted
accidentally sooner or later. PRs must include tests for all
changed/updated/fixed behaviors. See testing the engine for instructions on
writing and running engine tests.
Checklist
Before you create this PR confirm that it meets all requirements listed below by checking the relevant checkboxes (
[x]
). This will ensure a smooth and quick review process.Breaking Change
Did any tests fail when you ran them? Please read handling breaking changes.