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

Change new QueueUserWorkItem method to use TState #25193

Closed
stephentoub opened this issue Feb 26, 2018 · 12 comments
Closed

Change new QueueUserWorkItem method to use TState #25193

stephentoub opened this issue Feb 26, 2018 · 12 comments
Assignees
Labels
api-approved API was approved in API review, it can be implemented area-System.Threading
Milestone

Comments

@stephentoub
Copy link
Member

In .NET Core 2.1 we've added this new overload:

public static bool QueueUserWorkItem(WaitCallback callBack, object state, bool preferLocal)

We should change it to instead be:

public static bool QueueUserWorkItem<TState>(Action<TState> callBack, TState state, bool preferLocal)

This has several benefits:

  1. Action<object> with object state can be used, without a mismatch of delegate signatures. Action<object> is now commonly used in these situations.
  2. We can now avoid boxing value type arguments passed in.
  3. And because of (2) and value tuples, we can easily pass any number of arguments in without allocating a separate object to store them all.

We should fix this before we ship 2.1.

cc: @benaadams, @davidfowl, @kouvel

@benaadams
Copy link
Member

benaadams commented Feb 26, 2018

So very much for this!

Action and Action<T> is everywhere and interloping with WaitCallback needs a wrapper lambda which means you loose the state field QueueUserWorkItem(lamda, Action)

readonly static WaitCallback lamda = state => ((Action)state)();

Which also means for Action<T> you have to allocate an additional closure to capture the state in a regular Action

@davidfowl
Copy link
Member

YESSSS 😄

@jkotas
Copy link
Member

jkotas commented Feb 26, 2018

We can now avoid boxing value type arguments passed in.

But the implementation is still going to allocate the workitem on the heap, right? Isn't it just shifting where the boxing happens?

@stephentoub
Copy link
Member Author

stephentoub commented Feb 26, 2018

Isn't it just shifting where the boxing happens?

I'm not following. The ThreadPool allocates an IThreadPoolWorkItem implementation to store into the queue. That IThreadPoolWorkItem contains the delegate, the object state, and additional state like ExecutionContext. That's true whether or not the object state is a value type that was boxed. The boxing is yet another allocation on top of that work item object.

If you mean the value type is still going to end up on the heap, then yes. But it's going to end up there as part of the one object rather than having a separate one allocated for it.

@jkotas
Copy link
Member

jkotas commented Feb 26, 2018

Right, that's what I meant. So it saves ~3 pointers worth of allocation per work item. This saving does not depend on the state size. we can easily pass any number of arguments in without allocating an object to store them all made it sound like you can somehow pass in arbitrarily large state for free. (And the price you pay for this is larger code.)

@stephentoub
Copy link
Member Author

made it sound like you can somehow pass in arbitrarily large state for free

That's not what I intended to suggest, and in general I'd expect the number to be small, e.g. 2, for example another state-accepting delegate with a different type and the associated state to go with it.

@omariom
Copy link
Contributor

omariom commented Feb 26, 2018

@jkotas may not like it but what if ThreadPoolWorkItem<TState>? :)

@davidfowl
Copy link
Member

It'll eventually get boxed when the in ExecutionContext.Run happens.

@jkotas
Copy link
Member

jkotas commented Feb 26, 2018

ThreadPoolWorkItem<TState>

I expect that the implementation of the proposed API is going to use type like this internally. Potentially two types like this if it does the optimization for default execution context like the current QueueUserWorkItem.

@stephentoub
Copy link
Member Author

I expect that the implementation of the proposed API is going to use type like this internally. Potentially two types like this if it does the optimization for default execution context like the current QueueUserWorkItem.

Yup.

@stephentoub stephentoub self-assigned this Feb 26, 2018
@stephentoub stephentoub changed the title Change new QueueUserWorkItem method to use T Change new QueueUserWorkItem method to use TState Feb 26, 2018
@davidfowl
Copy link
Member

It'll eventually get boxed when the in ExecutionContext.Run happens.

Actually, I'm wrong here, I forget we pass the work item itself as the state!

@stephentoub
Copy link
Member Author

Fixed.

Dotnet-GitSync-Bot referenced this issue in Dotnet-GitSync-Bot/corefx Oct 29, 2019
…464)

ReadAsyncInternal is correctly passing its token into the two call sites where it delegates directly to the underlying stream, but in one place it calls through ReadBufferAsync, which is currently not defined to take a token.  Fix that, and pass the token through.

Signed-off-by: dotnet-bot <dotnet-bot@microsoft.com>
jkotas referenced this issue in dotnet/corefx Oct 30, 2019
…464)

ReadAsyncInternal is correctly passing its token into the two call sites where it delegates directly to the underlying stream, but in one place it calls through ReadBufferAsync, which is currently not defined to take a token.  Fix that, and pass the token through.

Signed-off-by: dotnet-bot <dotnet-bot@microsoft.com>
Dotnet-GitSync-Bot referenced this issue in Dotnet-GitSync-Bot/corefx Nov 15, 2019
…464) (dotnet#27501)

ReadAsyncInternal is correctly passing its token into the two call sites where it delegates directly to the underlying stream, but in one place it calls through ReadBufferAsync, which is currently not defined to take a token.  Fix that, and pass the token through.

Signed-off-by: dotnet-bot <dotnet-bot@microsoft.com>
@msftgits msftgits transferred this issue from dotnet/corefx Jan 31, 2020
@msftgits msftgits added this to the 2.1.0 milestone Jan 31, 2020
@ghost ghost locked as resolved and limited conversation to collaborators Dec 18, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
api-approved API was approved in API review, it can be implemented area-System.Threading
Projects
None yet
Development

No branches or pull requests

6 participants