I'm playing around with ManualResetValueTaskSourceCore, yet it seems even in this basic usage I have some sort of bug/misunderstanding.
The (only once) awaited ValueTask does never complete.
If the call to mre.SetResult is done before awaiting the ValueTask it works as expected.
internal struct ManualResetValueTaskSource<T> : IValueTaskSource<T>
{
private ManualResetValueTaskSourceCore<T> _taskSource = new();
public short Version => _taskSource.Version;
public ManualResetValueTaskSource()
{
_taskSource.RunContinuationsAsynchronously = true;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal ValueTask<T> GetTask() => new(this, _taskSource.Version);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void SetResult(T result) => _taskSource.SetResult(result);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void Reset() => _taskSource.Reset();
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public T GetResult(short token) => _taskSource.GetResult(token);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ValueTaskSourceStatus GetStatus(short token) => _taskSource.GetStatus(token);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void OnCompleted(Action<object?> continuation, object? state, short token, ValueTaskSourceOnCompletedFlags flags) => _taskSource.OnCompleted(continuation, state, token, flags);
}
internal static class Program
{
private static async Task Main()
{
var mre = new ManualResetValueTaskSource<int>();
Task.Run(async () =>
{
await Task.Delay(250);
mre.SetResult(123);
});
var result = await mre.GetTask();
Console.WriteLine(result);
}
}
You are passing value type in constructor here:
internal ValueTask<T> GetTask() => new(this, _taskSource.Version);
After this you capture value type local variable in closure here:
Task.Run(async () =>
{
await Task.Delay(250);
mre.SetResult(123);
});
That means you are completing copy of mre inside anonymous function. If you change ManualResetValueTaskSource to class code works.
Related
So I was trying to make a simple awaitable struct that allow my to return a bool:
// define a special container for returning results
public struct BoolResult {
public bool Value;
public BoolAwaiter GetAwaiter () {
return new BoolAwaiter(Value);
}
}
// make the interface task-like
public readonly struct BoolAwaiter : INotifyCompletion {
private readonly bool _Input;
// wrap the async operation
public BoolAwaiter (bool value) {
_Input = value;
}
// is task already done (yes)
public bool IsCompleted {
get { return true; }
}
// wait until task is done (never called)
public void OnCompleted (Action continuation) => continuation?.Invoke();
// return the result
public bool GetResult () {
return _Input;
}
}
And I was using it like:
private async BoolResult LoadAssets (string label) {
//
// some await asyncFunction here
//
// then at the end
return new BoolResult { Value = true };
}
But I still get this compile error:
error CS1983: The return type of an async method must be void, Task or Task<T>
I thought my BoolResult was already Task-like? What's the issue here?
How would you rewrite TaskOfTResult_MethodAsync to avoid the error: Since this is an async method, the return expression must be of type int rather than Task<int>.
private static async Task<int> TaskOfTResult_MethodAsync()
{
return Task.Run(() => ComplexCalculation());
}
private static int ComplexCalculation()
{
double x = 2;
for (int i = 1; i< 10000000; i++)
{
x += Math.Sqrt(x) / i;
}
return (int)x;
}
Simple; either don't make it async:
private static Task<int> TaskOfTResult_MethodAsync()
{
return Task.Run(() => ComplexCalculation());
}
or await the result:
private static async Task<int> TaskOfTResult_MethodAsync()
{
return await Task.Run(() => ComplexCalculation());
}
(adding the await here is more expensive in terms of the generated machinery, but has more obvious/reliable exception handling, etc)
Note: you could also probably use Task.Yield:
private static async Task<int> TaskOfTResult_MethodAsync()
{
await Task.Yield();
return ComplexCalculation();
}
(note that what this does depends a lot on the sync-context, if one)
I have static class full of extension methods where each of the methods is asynchronous and returns some value - like this:
public static class MyContextExtensions{
public static async Task<bool> SomeFunction(this DbContext myContext){
bool output = false;
//...doing stuff with myContext
return output;
}
public static async Task<List<string>> SomeOtherFunction(this DbContext myContext){
List<string> output = new List<string>();
//...doing stuff with myContext
return output;
}
}
My goal is to be able to invoke any of these methods from a single method in another class and return their result as an object. It would look something like this:
public class MyHub: Hub{
public async Task<object> InvokeContextExtension(string methodName){
using(var context = new DbContext()){
//This fails because of invalid cast
return await (Task<object>)typeof(MyContextExtensions).GetMethod(methodName).Invoke(null, context);
}
}
}
The problem is that the cast fails. My dilemma is that I cannot pass any type parameters to the "InvokeContextExtension" method because it is part of a SignalR hub and is invoked by javascript. And to a certain extent I don't care about the return type of the extension method because it is just going to get serialized to JSON and sent back to the javascript client. However I do have to cast the value returned by Invoke as a Task in order to use the await operator. And I have to supply a generic parameter with that "Task" otherwise it will treat the return type as void. So it all comes down to how do I successfully cast Task with generic parameter T to a Task with a generic parameter of object where T represents the output of the extension method.
You can do it in two steps - await the task using the base class, then harvest the result using reflection or dynamic:
using(var context = new DbContext()) {
// Get the task
Task task = (Task)typeof(MyContextExtensions).GetMethod(methodName).Invoke(null, context);
// Make sure it runs to completion
await task.ConfigureAwait(false);
// Harvest the result
return (object)((dynamic)task).Result;
}
Here is a complete running example that puts in context the above technique of calling Task through reflection:
class MainClass {
public static void Main(string[] args) {
var t1 = Task.Run(async () => Console.WriteLine(await Bar("Foo1")));
var t2 = Task.Run(async () => Console.WriteLine(await Bar("Foo2")));
Task.WaitAll(t1, t2);
}
public static async Task<object> Bar(string name) {
Task t = (Task)typeof(MainClass).GetMethod(name).Invoke(null, new object[] { "bar" });
await t.ConfigureAwait(false);
return (object)((dynamic)t).Result;
}
public static Task<string> Foo1(string s) {
return Task.FromResult("hello");
}
public static Task<bool> Foo2(string s) {
return Task.FromResult(true);
}
}
In general, to convert a Task<T> to Task<object>, I would simply go for the straightforward continuation mapping :
Task<T> yourTaskT;
// ....
Task<object> yourTaskObject = yourTaskT.ContinueWith(t => (object) t.Result);
(documentation link here)
However, your actual specific need is to invoke a Task by reflection and obtain its (unknown type) result .
For this, you can refer to the complete dasblinkenlight's answer, which should fit your exact problem.
I'd like to provide an implementation which is IMHO the best combination of the earlier answers:
precise argument handling
no dynamic dispatch
general purpose extension method
Here you go:
/// <summary>
/// Casts a <see cref="Task"/> to a <see cref="Task{TResult}"/>.
/// This method will throw an <see cref="InvalidCastException"/> if the specified task
/// returns a value which is not identity-convertible to <typeparamref name="T"/>.
/// </summary>
public static async Task<T> Cast<T>(this Task task)
{
if (task == null)
throw new ArgumentNullException(nameof(task));
if (!task.GetType().IsGenericType || task.GetType().GetGenericTypeDefinition() != typeof(Task<>))
throw new ArgumentException("An argument of type 'System.Threading.Tasks.Task`1' was expected");
await task.ConfigureAwait(false);
object result = task.GetType().GetProperty(nameof(Task<object>.Result)).GetValue(task);
return (T)result;
}
You cannot cast Task<T> to Task<object>, because Task<T> is not covariant (it's not contravariant, either). The simplest solution would be to use some more reflection:
var task = (Task) mi.Invoke (obj, null) ;
var result = task.GetType ().GetProperty ("Result").GetValue (task) ;
This is slow and inefficient, but usable if this code is not executed often. As an aside, what is the use of having an asynchronous MakeMyClass1 method if you are going to block waiting for its result?
and Another possibility is to write an extension method to this purpose:
public static Task<object> Convert<T>(this Task<T> task)
{
TaskCompletionSource<object> res = new TaskCompletionSource<object>();
return task.ContinueWith(t =>
{
if (t.IsCanceled)
{
res.TrySetCanceled();
}
else if (t.IsFaulted)
{
res.TrySetException(t.Exception);
}
else
{
res.TrySetResult(t.Result);
}
return res.Task;
}
, TaskContinuationOptions.ExecuteSynchronously).Unwrap();
}
It is none-blocking solution and will preserve original state/exception of the Task.
The most efficient approach would be custom awaiter:
struct TaskCast<TSource, TDestination>
where TSource : TDestination
{
readonly Task<TSource> task;
public TaskCast(Task<TSource> task)
{
this.task = task;
}
public Awaiter GetAwaiter() => new Awaiter(task);
public struct Awaiter
: System.Runtime.CompilerServices.INotifyCompletion
{
System.Runtime.CompilerServices.TaskAwaiter<TSource> awaiter;
public Awaiter(Task<TSource> task)
{
awaiter = task.GetAwaiter();
}
public bool IsCompleted => awaiter.IsCompleted;
public TDestination GetResult() => awaiter.GetResult();
public void OnCompleted(Action continuation) => awaiter.OnCompleted(continuation);
}
}
with the following usage:
Task<...> someTask = ...;
await TaskCast<..., object>(someTask);
The limitation of this approach is that the result is not a Task<object> but an awaitable object.
I made a little extension method based on dasblinkenlight's answer:
public static class TaskExtension
{
public async static Task<T> Cast<T>(this Task task)
{
if (!task.GetType().IsGenericType) throw new InvalidOperationException();
await task.ConfigureAwait(false);
// Harvest the result. Ugly but works
return (T)((dynamic)task).Result;
}
}
Usage:
Task<Foo> task = ...
Task<object> = task.Cast<object>();
This way you can change T in Task<T> to anything you want.
For the best approach, without using reflection and dynamic ugly syntax, and without passing generic types. I would use two extension methods for achieving this goal.
public static async Task<object> CastToObject<T>([NotNull] this Task<T> task)
{
return await task.ConfigureAwait(false);
}
public static async Task<TResult> Cast<TResult>([NotNull] this Task<object> task)
{
return (TResult) await task.ConfigureAwait(false);
}
Usage:
Task<T1> task ...
Task<T2> task2 = task.CastToObject().Cast<T2>();
This my second approach, but not recommended:
public static async Task<TResult> Cast<TSource, TResult>([NotNull] this Task<TSource> task, TResult dummy = default)
{
return (TResult)(object) await task.ConfigureAwait(false);
}
Usage:
Task<T1> task ...
Task<T2> task2 = task.Cast((T2) default);
// Or
Task<T2> task2 = task.Cast<T1, T2>();
This my third approach, but not recommended: (similar to second one)
public static async Task<TResult> Cast<TSource, TResult>([NotNull] this Task<TSource> task, Type<TResult> type = null)
{
return (TResult)(object) await task.ConfigureAwait(false);
}
// Dummy type class
public class Type<T>
{
}
public static class TypeExtension
{
public static Type<T> ToGeneric<T>(this T source)
{
return new Type<T>();
}
}
Usage:
Task<T1> task ...
Task<T2> task2 = task.Cast(typeof(T2).ToGeneric());
// Or
Task<T2> task2 = task.Cast<T1, T2>();
This is not a good idea to mix await with dynamic/reflection invoke since await is a compiler instruction that generates a lot of code around invoked method and there is no real sense to "emulate" compiler work with more reflections, continuations, wrappers and etc.
Since what you need is to manage your code at RUN TIME then forget the asyc await syntax sugar which works at compile time. Rewrite SomeFunction and SomeOtherFunction without them, and start operations in your own tasks created at run time. You will get the same behavior but with crystal clear code.
Here's a dumbed-down version of what I want to do:
private static int Inc(int input)
{
return input + 1;
}
private static async Task<int> IncAsync(int input)
{
await Task.Delay(200);
return input + 1;
}
private static async Task<IEnumerable<TResult>> GetResultsAsync<TInput, TResult>(Func<TInput, TResult> func, IEnumerable<TInput> values)
{
var tasks = values.Select(value => Task.Run(() => func(value)))
.ToList();
await Task.WhenAll(tasks);
return tasks.Select(t => t.Result);
}
public async void TestAsyncStuff()
{
var numbers = new[] { 1, 2, 3, 4 };
var resultSync = await GetResultsAsync(Inc, numbers); // returns IEnumerable<int>
Console.WriteLine(string.Join(",", resultSync.Select(n => $"{n}")));
// The next line is the important one:
var resultAsync = await GetResultsAsync(IncAsync, numbers); // returns IEnumerable<Task<int>>
}
So basically, GetResultsAsync() is intended to be a generic method that will get the results of a function for a set of input values. In TestAsyncStuff() you can see how it would work for calling a synchronous function (Inc()).
The trouble comes when I want to call an asynchronous function (IncAsync()). The result I get back is of type IEnumerable<Task<int>>. I could do a Task.WhenAll() on that result, and that works:
var tasksAsync = (await GetResultsAsync(IncAsync, numbers)).ToList();
await Task.WhenAll(tasksAsync);
var resultAsync = tasksAsync.Select(t => t.Result);
Console.WriteLine(string.Join(",", resultAsync.Select(n => $"{n}")));
But I'd like to tighten up the code and do the await inline. It should look something like this:
var resultAsync = await GetResultsAsync(async n => await IncAsync(n), numbers);
But that also returns an IEnumerable<Task<int>>! I could do this:
var resultAsync = await GetResultsAsync(n => IncAsync(n).GetAwaiter().GetResult(), numbers);
And that works... but from what I've seen, use of Task.GetAwaiter().GetResult() or Task.Result is not encouraged.
So what is the correct way to do this?
You should create two overloads of GetResultsAsync. One should accept a 'synchronous' delegate which returns TResult. This method will wrap each delegate into a task, and run them asynchronously:
private static async Task<IEnumerable<TResult>> GetResultsAsync<TInput, TResult>(
Func<TInput, TResult> func, IEnumerable<TInput> values)
{
var tasks = values.Select(value => Task.Run(() => func(value)));
return await Task.WhenAll(tasks);
}
The second overload will accept an 'asynchronous' delegate, which returns Task<TResult>. This method doesn't need to wrap each delegate into a task, because they are already tasks:
private static async Task<IEnumerable<TResult>> GetResultsAsync<TInput, TResult>(
Func<TInput, Task<TResult>> func, IEnumerable<TInput> values)
{
var tasks = values.Select(value => func(value));
return await Task.WhenAll(tasks);
}
You even can call the second method from the first one to avoid code duplication:
private static async Task<IEnumerable<TResult>> GetResultsAsync<TInput, TResult>(
Func<TInput, TResult> func, IEnumerable<TInput> values)
{
return await GetResultsAsync(x => Task.Run(() => func(x)), values);
}
NOTE: These methods don't simplify your life a lot. The same results can be achieved with
var resultSync = await Task.WhenAll(numbers.Select(x => Task.Run(() => Inc(x))));
var resultAsync = await Task.WhenAll(numbers.Select(IncAsync));
I'd say that your concern is a stylistic one: you want something that reads better. For your first case consider:
var resultSync= numbers.AsParallel()/*.AsOrdered()*/.Select(Inc);
on the grounds that Plinq already does what you're trying to do: It parallelizes IEnumerables. For your second case, there's no point in creating Tasks around Tasks. The equivalent would be:
var resultAsync = numbers.AsParallel()./*AsOrdered().*/Select(n => IncAsync(n).Result);
but I like Sergey's await Task.WhenAll(numbers.Select(IncAsync)) better.
Perhaps what I really like is a Linq style pair of overloads:
var numbers = Enumerable.Range(1,6);
var resultSync = await Enumerable.Range(1,6).SelectAsync(Inc);
var resultAsync = await Enumerable.Range(1,100).SelectAsync(IncAsync);
Console.WriteLine("sync" + string.Join(",", resultSync));
Console.WriteLine("async" + string.Join(",", resultAsync));
static class IEnumerableTasks
{
public static Task<TResult[]> SelectAsync<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TResult> func)
{
return Task.WhenAll( source.Select(async n => await Task.Run(()=> func(n))));
}
public static Task<TResult[]> SelectAsync<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, Task<TResult>> func)
{
return Task.WhenAll(source.Select(func));
}
}
static int Inc(int input)
{
Task.Delay(1000).Wait();
return input+1;
}
static async Task<int> IncAsync(int input)
{
await Task.Delay(1000);
return input + 1;
}
Which, incidentally, if you change Range(1,6) to Range(1,40) shows the advantage of async. On my machine, the timing for the sync can rise steeply where the async version stays at a second or so even for Range(1, 100000)
How can i create new task with multiple params, return type and createoptions by using new?
Task<int> task = Task<int>(DoWork(0,1));
private static Task<int> DoWork(int a, int b)
{
return null;
}
this is working fine.... but when i try create task with new keyword so i can set startoptions to longrunning like this:
Task<int> task = new Task<int>(DoWork(0,1), TaskCreationOptions.LongRunning);
I am always getting some errs like:
Argument 1: cannot convert from 'System.Threading.Tasks.Task' to 'System.Func'
I tried xx different variants but no luck. I understand i am probably wrongly passing param "Func function". I would like to avoid anonymous function. thx.
You can pass the method as a Lambda Expression:
Task<Task<int>> task = new Task<Task<int>>(() => DoWork(0,1), TaskCreationOptions.LongRunning);
Although, it is recommended to use Task.Factory.StartNew if possible, so you return a Hot Task instead of a Cold Task (which required you to call Task.Start).
Task<Task<int>> task = Task.Factory.StartNew(() => DoWork(0,1), TaskCreationOptions.LongRunning);
public SomeClass()
{
var func = new Func<int, int, int>((i1, i2) => i1 + i2);
Task.Factory.StartNew(() =>
Debug.WriteLine(func(1, 2)), TaskCreationOptions.LongRunning);
Task.Factory.StartNew(() =>
Debug.WriteLine(DoWork(2, 3).Result), TaskCreationOptions.LongRunning);
}
private static Task<int> DoWork(int a, int b)
{
return Task.FromResult(a + b);
}
The constructor for Task<T> requires a Func<T> argument.
Task<int> task = Task<int>(DoWork(0,1));
is attempting to call the DoWork method and pass the returnedTask<int> as the parameter into the task task. You need to pass a Func<int> instead by changing the type of DoWork to:
private static int DoWork(int a, int b) { ... }
then you can do:
Task<int> task = new Task<int>(() => DoWork(0,1), TaskCreationOptions.LongRunning);