Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

use ThreadPool to execute spawn_worker(fn) #3836

Merged
merged 13 commits into from
Oct 21, 2019
Merged

use ThreadPool to execute spawn_worker(fn) #3836

merged 13 commits into from
Oct 21, 2019

Conversation

Lawliet-Chan
Copy link
Contributor

@Lawliet-Chan Lawliet-Chan commented Oct 16, 2019

Hi, I use ThreadPool to implement the spawn_worker() instead of std::thread::spawn.
The pool size is set available CPU nums.
[clabot:check]

@parity-cla-bot
Copy link

It looks like @CrocdileChan hasn't signed our Contributor License Agreement, yet.

The purpose of a CLA is to ensure that the guardian of a project's outputs has the necessary ownership or grants of rights over all contributions to allow them to distribute under the chosen licence.
Wikipedia

You can read and sign our full Contributor License Agreement at the following URL: https://cla.parity.io

Once you've signed, please reply to this thread with [clabot:check] to prove it.

Many thanks,

Parity Technologies CLA Bot

@Lawliet-Chan
Copy link
Contributor Author

[clabot:check]

@parity-cla-bot
Copy link

It looks like @CrocdileChan signed our Contributor License Agreement. 👍

Many thanks,

Parity Technologies CLA Bot

@Lawliet-Chan
Copy link
Contributor Author

Lawliet-Chan commented Oct 16, 2019 via email

@parity-cla-bot
Copy link

It looks like @CrocdileChan signed our Contributor License Agreement. 👍

Many thanks,

Parity Technologies CLA Bot

Copy link
Contributor

@tomusdrw tomusdrw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use tabs not spaces and please avoid reformatting the code that you don't change.

marker::PhantomData,
sync::Arc,
};
extern crate num_cpus;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We use edition = 2018, this is not needed.

Suggested change
extern crate num_cpus;

assert_eq!(pool.status().ready, 1);
assert_eq!(pool.ready().next().unwrap().is_propagateable(), false);
}
use super::*;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We use tabs in the codebase, please avoid reformattings.

@@ -16,6 +16,8 @@ futures-timer = "0.4.0"
hyper = "0.12.35"
hyper-tls = "0.3.2"
log = "0.4.8"
threadpool = "1.0"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Latest version is 1.7, can you update the numbers here?

@@ -16,6 +16,8 @@ futures-timer = "0.4.0"
hyper = "0.12.35"
hyper-tls = "0.3.2"
log = "0.4.8"
threadpool = "1.0"
num_cpus = "1.6"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
num_cpus = "1.6"
num_cpus = "1.10"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sure

@@ -39,6 +39,8 @@ use std::{
sync::Arc,
};

extern crate num_cpus;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should not be needed in 2018 edition?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm sorry I don't understand what you mean.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The usage of extern crate xxx should not be needed anymore.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup, just remove that line, fix the tests and we are good to go.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are build results below the comments section on github:
https://gitlab.parity.io/parity/substrate/-/jobs/249361

Actually it's not a test failing, but you need to run cargo check locally and commit changes in Cargo.lock file.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, I see.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have committed the change of Cargo.lock . But there is a trouble, when I run 'cargo check' in the path ' ~/substrate/ ' , it shows that futures-io-preview can't compile.

error[E0106]: missing lifetime specifier
--> /Users/ChenXinRan/.cargo/registry/src/code.aliyun.com-738b7dba08a2a41e/futures-io-preview-0.3.0-alpha.19/src/lib.rs:292:28
|
292 | -> Poll<Result<&[u8]>>;
| ^ expected lifetime parameter
|
= help: this function's return type contains a borrowed value, but the signature does not say which one of argument 2's 2 lifetimes it is borrowed from

error[E0106]: missing lifetime specifier
--> /Users/ChenXinRan/.cargo/registry/src/code.aliyun.com-738b7dba08a2a41e/futures-io-preview-0.3.0-alpha.19/src/lib.rs:559:32
|
559 | -> Poll<Result<&[u8]>>
| ^ expected lifetime parameter
...
571 | deref_async_buf_read!();
| ------------------------ in this macro invocation
|
= help: this function's return type contains a borrowed value, but the signature does not say which one of cx's 2 lifetimes it is borrowed from

error[E0106]: missing lifetime specifier
--> /Users/ChenXinRan/.cargo/registry/src/code.aliyun.com-738b7dba08a2a41e/futures-io-preview-0.3.0-alpha.19/src/lib.rs:559:32
|
559 | -> Poll<Result<&[u8]>>
| ^ expected lifetime parameter
...
575 | deref_async_buf_read!();
| ------------------------ in this macro invocation
|
= help: this function's return type contains a borrowed value, but the signature does not say which one of cx's 2 lifetimes it is borrowed from

error[E0106]: missing lifetime specifier
--> /Users/ChenXinRan/.cargo/registry/src/code.aliyun.com-738b7dba08a2a41e/futures-io-preview-0.3.0-alpha.19/src/lib.rs:584:28
|
584 | -> Poll<Result<&[u8]>>
| ^ expected lifetime parameter
|
= help: this function's return type contains a borrowed value, but the signature does not say which one of cx's 2 lifetimes it is borrowed from

error[E0106]: missing lifetime specifier
--> /Users/ChenXinRan/.cargo/registry/src/code.aliyun.com-738b7dba08a2a41e/futures-io-preview-0.3.0-alpha.19/src/lib.rs:597:32
|
597 | -> Poll<Result<&[u8]>>
| ^ expected lifetime parameter
...
609 | delegate_async_buf_read_to_stdio!();
| ------------------------------------ in this macro invocation
|
= help: this function's return type contains a borrowed value, but the signature does not say which one of argument 2's 2 lifetimes it is borrowed from

error[E0106]: missing lifetime specifier
--> /Users/ChenXinRan/.cargo/registry/src/code.aliyun.com-738b7dba08a2a41e/futures-io-preview-0.3.0-alpha.19/src/lib.rs:597:32
|
597 | -> Poll<Result<&[u8]>>
| ^ expected lifetime parameter
...
613 | delegate_async_buf_read_to_stdio!();
| ------------------------------------ in this macro invocation
|
= help: this function's return type contains a borrowed value, but the signature does not say which one of argument 2's 2 lifetimes it is borrowed from

error: aborting due to 6 previous errors

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But your code seem to be compiling well on the CI machine.. Make sure you have the latest version of rustc and stable/nightly toolchains installed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here is my rust version.

rustc 1.38.0-nightly (69656fa4c 2019-07-13)
rustc 1.40.0-nightly (ddf43867a 2019-09-26)
rustup 1.19.0 (2af131cf9 2019-09-08)

@Lawliet-Chan
Copy link
Contributor Author

OH, today the substrate is already updated. Just a moment, I merge the newest Cargo.lock

@Lawliet-Chan
Copy link
Contributor Author

@tomusdrw I don't understand why CI/CD still tests failing. I have merge the newest substrate/Cargo.lock to mine and run 'cargo check'. But it still shows these.
And I've send message to you on the riot.
Shall we talk on the riot?

@tomusdrw
Copy link
Contributor

tomusdrw commented Oct 18, 2019

@CrocdileChan I didn't get anything on Riot, my handle @todr:matrix.parity.io.

I've just pushed https://github.com/paritytech/substrate/pull/new/pull-3836 with updated Cargo.lock - you can cherry-pick the commit from there.

Here is the commit: a129240

@@ -39,6 +39,8 @@ use std::{
sync::Arc,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
sync::Arc,
sync::{Arc, Mutex},

@@ -39,6 +39,8 @@ use std::{
sync::Arc,
};

use threadpool::ThreadPool;
use std::sync::Mutex;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
use std::sync::Mutex;

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sure, I've already formatted it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bkchr @tomusdrw I've already fixed it and CI/CD run success a few days ago. Could you please merge this PR?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is not only about the CI finishing, also the reviewers need to be happy.

@@ -36,9 +36,10 @@
use std::{
fmt,
marker::PhantomData,
sync::Arc,
sync::{Arc,Mutex},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use parking_lot::Mutex instaed of std::sync::Mutex.

/// Note that we should avoid that if we switch to future-based runtime in the future,
/// alternatively:
fn spawn_worker(&self, f: impl FnOnce() -> () + Send + 'static) {
self.thread_pool.lock().unwrap().execute(f);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When you switch to parking_lot::Mutex, this will be just:

Suggested change
self.thread_pool.lock().unwrap().execute(f);
self.thread_pool.lock().execute(f);

@tomusdrw tomusdrw merged commit b7627c4 into paritytech:master Oct 21, 2019
@tomaka
Copy link
Contributor

tomaka commented Oct 21, 2019

What is the reason of this change? Using a thread pool for threads that we create every 6 seconds seems like a very premature optimization. And now instead of having either 0 or 1 thread alive at any given point in time, we maintain 4 or 8 (your number of CPUs) of them.

@tomusdrw
Copy link
Contributor

We don't really know the kind of work users of our library will do in offchain workers. I can easily imagine that they will take way more than 6 seconds. Using fixed-size thread pool is in my mind is cheaper and safer than spawning a new thread for each task, although on the second though having this number set to as high as number of cores indeed seems wasteful for most of the cases we support currently (especially given that we don't run per-module workers in parallel). What's your suggestion then? Do you think we should revert it? Lower the number or make it configurable?

@tomaka
Copy link
Contributor

tomaka commented Oct 21, 2019

What's your suggestion then?

My suggestion is to not care about performances unless something actually shows that there's a bottleneck. Instead, keep the code as clear and simple as possible.

It's not a big deal to have a threads pool here, but I also don't understand why that kind of changes are made.

@tomusdrw
Copy link
Contributor

My suggestion is to not care about performances unless something actually shows that there's a bottleneck.

Sure thing, I agree 100%. But we are building a library here, we won't know all possible cases that the bottleneck might happen. IMHO it's better be safe and cap the number of threads that offchain workers may consume than to allow spawning unlimited number in case someone just has a buggy implementation of a worker.

Instead, keep the code as clear and simple as possible.

I don't find the current implementation that much more convoluted and unclear to justify rejecting sensible external contribution.

@tomaka
Copy link
Contributor

tomaka commented Oct 21, 2019

IMHO it's better be safe and cap the number of threads that offchain workers may consume than to allow spawning unlimited number in case someone just has a buggy implementation of a worker.

If someone has a buggy implementation of a worker: before this PR we have a resource leak, and after this PR we silently not spawn further workers. Both solutions are kind of crappy.

@@ -58,6 +60,7 @@ pub struct OffchainWorkers<Client, Storage, Block: traits::Block> {
client: Arc<Client>,
db: Storage,
_block: PhantomData<Block>,
thread_pool: Mutex<ThreadPool>,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Mutex isn't needed.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ThreadPool isn't Send/Sync

Copy link
Contributor

@tomaka tomaka Oct 21, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What you said surprised me a lot, so I checked.

https://github.com/rust-threadpool/rust-threadpool/blob/21a70c7e8b19fb73a9f3f44a55ca1b7333d804f9/src/lib.rs#L1212-L1228

I don't see a test for Sync for ThreadPool, but I would be surprised if it wasn't Sync as well.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rust-threadpool/rust-threadpool#96

There is an issue for this.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants