Run any C# method async. Possible? - c#

With Task.Run() you can run any method async, like
public int Increase(int val)
{
return val + 1
}
int increased = await Task.Run ( () => return Increase(3) );
Is it possible to create an extension method, to just run any method as async like
var val = 1;
int increased = await Increased(3).AsAsync();

There is no way you could write an AsAsync method that would do what you're suggesting. In the code Increased(3).AsAsync() You have already synchronously executed Increased(3) and computed its result before AsAsync is called. It's too late to not execute that code before continuing.

If you have a CPU bound task and you want to use async as a convenient wrapper also for CPU bound operations, you can define an extension (vaguely based on this GetTask example)
public static class AsyncExtensions
{
public static Task<U> AsCpuBoundAsync<T,U>(this Func<T,U> func, T t)
{
return Task.Run(() => func(t));
}
}
to wrap a function
public static int Increase(int val)
{
//doing CPU bound activities...
return val + 1;
}
as follows
int increased = await ((Func<int,int>)(t =>
Increase(t))).AsCpuBoundAsync(3);

Related

C#: Could you explain how TaskFactory executes asynchronously method which is passed as a parameter to StartNew method?

I have a problem with understanding of execution of asynchronously method which is passed as a parameter to StartNew method of TaskFactory. Could you explain me how exactly it will work?
I have UserInfo class which contains user identifier.
public sealed class UserInfo
{
[ThreadStatic]
public static Guid UserId;
}
I have my custom implementation of TaskScheduler. I don't show a full code of this class because it isn't interesting. This class set user identifier to current thread. Set user identifier to UserId variable.
public sealed class CustomTaskScheduler : TaskScheduler
{
// Sets user information to the variable which is marked ThreadStatisAttribute.
}
I created my custom TaskFactory which takes custom scheduler as a parameter of constructor.
public sealed class CustomTaskFactory : TaskFactory
{
public CustomTaskFactory(CustomTaskScheduler taskScheduler) : base(taskScheduler) { }
}
And finally I have the Service class which performs asynchronously operations.
public sealed class Service
{
private readonly CustomTaskScheduler customTaskScheduler;
private readonly CustomTaskFactory customTaskFactory;
private readonly SomeClient someClient;
public Service()
{
this.customTaskScheduler = new CustomTaskScheduler();
this.customTaskFactory = new CustomTaskFactory(this.customTaskScheduler);
this.someClient = new SomeClient();
}
public void DoSomething(string param)
{
this.customTaskFactory.StartNew(() => testAsync(param)).Unwrap().Wait();
// This method will use the result which is given by async operation which is called above.
DoSomethingElseSynchronously();
}
private async Task DoSomethingAsync()
{
Thread.Sleep(1000);
int result1 = await this.customTaskFactory.StartNew(() => PerformAsyncOperation(default(int))).Unwrap();
Thread.Sleep(1000);
int result2 = await this.customTaskFactory.StartNew(() => PerformAsyncOperation(default(int))).Unwrap();
int sum = result1 + result2;
}
private async Task<int> PerformAsyncOperation(int x)
{
Thread.Sleep(1000);
return await this.customTaskFactory.StartNew(() => CallClientAsync(x)).Unwrap();
}
private async Task<int> CallClientAsync(int x)
{
Thread.Sleep(1000);
int resultObtainedFromClient1 = await this.customTaskFactory.StartNew(async () => await this.someClient.GetAsync(x)).Unwrap();
Thread.Sleep(1000);
int resultObtainedFromClient2 = await this.customTaskFactory.StartNew(async () => await this.someClient.GetAsync(x)).Unwrap();
int result = resultObtainedFromClient1 + resultObtainedFromClient2;
return result;
}
}
Well, to be fair, I have two questions:
What is the difference between calls await this.customTaskFactory.StartNew(async () => await this.someClient.GetAsync(x)).Unwrap() and await this.customTaskFactory.StartNew(() => this.someClient.GetAsync(x)).Unwrap() I would like to recall that I am interested in my ThreadStatic variable UserId. As I understand the first call will be executed in the same thread which called StartNew method and my thread static field will be filled in this case. In the second call I puts asynchronous method as a parameter of StartNew method. That means that task will contain asynchronous method which maybe will be executed by another thread and this another thread will not contain my UserId variable.
I need to be sure that each thread will contain not empty UserId variable. Are there any cases when I lose UserId data? How to prevent it?
Thanks in advance

Is it safe to pass Task as method parameter?

Consider the following code:
public class Program {
static void Main(string[] args) {
Generate();
}
static void Generate() {
Task t = null;
t = Task.Run(() => {
MyClass myClass = new MyClass();
myClass.ContinueTask(t);
});
Console.ReadLine();
}
}
public class MyClass {
public void ContinueTask(Task t) {
t.ContinueWith(x => {
Console.WriteLine("Continue here...");
});
}
}
Is it safe to pass t as parameter as so or is it better to directly start a new task inside MyClass?
This is unsafe because t might not be assigned at the point where it is used. In fact this is a data race.
Even if you fixed that it would be bad architecture. Why does ContinueTask need to know that it is continuing with something. This is a not a concern that should be located here. ContinueTask should perform it's work assuming that its antecedent has completed already.
It's hard to tell what you are trying to accomplish. What's wrong with sequencing your code like this:?
static async Task Generate() {
var t = Task.Run(() => {
//... other code ...
});
MyClass myClass = new MyClass();
await t;
myClass.ContinueTask();
Console.ReadLine();
}
await is perfect for sequencing tasks.
reusing the Task object
What do you mean by that? A task cannot be reused. It cannot run twice. All that your ContinueWith does is logically wait for the antecedent and then run the lambda. Here, the task serves as an event basically.
ContinueWith does not modify the task it is being called on. It creates a new task.
I've reduced your code down to this example:
public Task<int> Parse()
{
Task<int> t = null;
t = Task.Run(() => this.Read(t));
return t;
}
public Task<int> Read(Task<int> t)
{
return t.ContinueWith(v => 42);
}
I think that has the same underlying structure.
This causes a dead-lock. I suspect your code does too. So I think it's unsafe.

Async Method does not return control back to caller

Control is returned back to main method, before UploadToServer executes completely. Should I remove Task.Run() from UploadToServer or do a WaitAll explicitly?
public class Uploader
{
async public Task<int> Upload(int i)
{
int incremented = 0;
var t = UploadToServer(i);
if (t != null)
{
incremented = await t;
}
return incremented;
}
async private Task<int> UploadToServer(int i)
{
int incremented = 0;
await Task.Run(() =>
{
//Console.ReadLine();
//Actual upload operation
incremented = i + 1;
});
return incremented;
}
}
class Program
{
static void Main(string[] args)
{
Uploader upl = new Uploader();
var res = upl.Upload(10).Result;
}
}
When you await on async methods, the control is yielded back to the caller. What you're experiencing is proper async behavior.
If you dont want the method to return while the operation is executing, execute it synchronously.
If what you're attempting to do is I/O bound work (like upload something to a server), dont use Task.Run, as I/O bound is naturally exposed with async endpoints, eliminating the need for unnecessary threads in the process. Look at HttpClient as an example which exposes a bunch of XXXAsync methods.
try in this way
private Task<int> UploadToServer(int i)
{
int incremented = 0;
return Task.Run(() =>
{
//Console.ReadLine();
//Actual upload operation
return incremented = i + 1;
});
}
or in this way
private async Task<int> UploadToServer(int i)
{
return await Task.Run(() => DoSomething(i)).Wait();
}
private int DoSomething(int i)
{
//Console.ReadLine();
//Actual upload operation
return i+1;
}
Note that these examples aren't particularly useful methods.
considers that the background thread should live its own life.
In your case I suppose that maybe you can use some async methods of the HttpClient class of the framework
Example
private async Task<int> GetWebPageHtmlSizeAsync()
{
var client = new HttpClient();
var html = await client.GetAsync("http://www.test.com/");
return html.Length;
}
UPDATE
I've tested this code and it worked
static void Main(string[] args)
{
Uploader upl = new Uploader();
var res = upl.Upload(10).Result;
}
public class Uploader
{
async public Task<int> Upload(int i)
{
int incremented = 0;
var t = UploadToServer(i);
if (t != null)
{
incremented = await t;
}
return incremented;
}
private async Task<int> UploadToServer(int i)
{
return await Task.Run(() => DoSomething(i));
}
private int DoSomething(int i)
{
//Console.ReadLine();
//Actual upload operation
Thread.Sleep(2000);
return i + 1;
}
}
main program waits 2 seconds before receive the right value and the control back.
Have a look at this Should I expose asynchronous wrappers for synchronous methods? article that explains when and how you should use asynchronous methods. In your specific example you aren't getting advantages from task.run. I have only provided to you one working example with your code.

Async methods with and without async modifier

What is the difference between methods Add1() and Add2()? Is there a difference at all? For all I know usage (as shown in method UsageTest()) is the same.
private async Task<int> Add1(int a, int b)
{
return await Task.Run(
() =>
{
Thread.Sleep(1000);
return a + b;
});
}
private Task<int> Add2(int a, int b)
{
return Task.Run(
() =>
{
Thread.Sleep(1000);
return a + b;
});
}
private async void UsageTest()
{
int a = await Add1(1, 2);
int b = await Add2(1, 3);
}
Semantically, they are practically equivalent.
The main difference is that Add1 has more overhead (for the async state machine).
There is also a smaller difference; Add1 will marshal back to its original context while Add2 will not. This can cause a deadlock if the calling code does not use await:
public void Button1_Click(..)
{
Add1().Wait(); // deadlocks
Add2().Wait(); // does not deadlock
}
I explain this deadlock situation in more detail on my blog and in a recent MSDN article.
Add1 will run synchronously until it encounters the await keyword. In this case, that will not have an effect because the await keyword is at the beginning of the method.
To see the effect of this, you can insert a Thread.Sleep() method into the beginning of Add1 and Add2, and notice that the method marked async blocks before it returns.

Change normal loop to Parallel loop

I have the following code:
static void Main(string[] args)
{
TaskExecuter.Execute();
}
class Task
{
int _delay;
private Task(int delay) { _delay = delay; }
public void Execute() { Thread.Sleep(_delay); }
public static IEnumerable GetAllTasks()
{
Random r = new Random(4711);
for (int i = 0; i < 10; i++)
yield return new Task(r.Next(100, 5000));
}
}
static class TaskExecuter
{
public static void Execute()
{
foreach (Task task in Task.GetAllTasks())
{
task.Execute();
}
}
}
I need to change the loop in Execute method to paralle with multiple threads, I tried the following, but it isn't working since GetAllTasks returns IEnumerable and not a list
Parallel.ForEach(Task.GetAllTasks(), task =>
{
//Execute();
});
Parallel.ForEach works with IEnumerable<T>, so adjust your GetAllTasks to return IEnumerable<Task>.
Also .net has widely used Task class, I would avoid naming own class like that to avoid confusion.
Parallel.ForEach takes an IEnumerable<TSource>, so your code should be fine. However, you need to perform the Execute call on the task instance that is passed as parameter to your lambda statement.
Parallel.ForEach(Task.GetAllTasks(), task =>
{
task.Execute();
});
This can also be expressed as a one-line lambda expression:
Parallel.ForEach(Task.GetAllTasks(), task => task.Execute());
There is also another subtle bug in your code that you should pay attention to. Per its internal implementation, Parallel.ForEach may enumerate the elements of your sequence in parallel. However, you are calling an instance method of the Random class in your enumerator, which is not thread-safe, possibly leading to race issues. The easiest way to work around this would be to pre-populate your sequence as a list:
Parallel.ForEach(Task.GetAllTasks().ToList(), task => task.Execute());
This worked on my linqpad. I just renamed your Task class to Work and also returned an IEnumerable<T> from GetAllTasks:
class Work
{
int _delay;
private Work(int delay) { _delay = delay; }
public void Execute() { Thread.Sleep(_delay); }
public static IEnumerable<Work> GetAllTasks()
{
Random r = new Random(4711);
for (int i = 0; i < 10; i++)
yield return new Work(r.Next(100, 5000));
}
}
static class TaskExecuter
{
public static void Execute()
{
foreach (Work task in Work.GetAllTasks())
{
task.Execute();
}
}
}
void Main()
{
System.Threading.Tasks.Parallel.ForEach(Work.GetAllTasks(), new Action<Work>(task =>
{
//Execute();
}));
}

Categories

Resources