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.
Related
I have a method shown bellow
static public async Task GetStudentDetails(studentinfo stu)
{
// here i am using webservice call
// do some other operations
}
and this method is called from another method as shown below:
static public void GetUIWindow((int a, int b)
{
someanothercall();
studentinfo s = new Studentinfo();
GetStudentDetails(s); // here how can i use await keyword ??
}
Here how can i use await keyword ??
how can i use await keyword ??
You await the task returned from GetStudentDetails:
await GetStudentDetails(s);
The compiler will then complain at you saying that you should change GetUIWindow to be async and return a Task. So go ahead and do that:
static public async Task GetUIWindowAsync(int a, int b)
Then do the same for all the places that call GetUIWindow. Rinse and repeat; it's async all the way.
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);
I am trying to execute parallel methods, but Form gets stuck whenever
I call them.
Please correct what I am doing wrong. Here is the Code:
public partial class Form1 : Form
{
private async void button1_Click(object sender, EventArgs e)
{
var itemList = new List<string>() { "Field1", "Field2", "Field3" };
await Task.WhenAll(itemList.Select(item =>
new WorkToDo(item).StartWork()
));
}
}
public class WorkToDo
{
private string id;
public WorkToDo(string id)
{
this.id = id;
}
public async Task<bool> StartWork()
{
Calculate();
Analyze();
SomeToDo();
var result = Save();
await Task.Delay(100);
return result;
}
private bool Calculate()
{
//Some complex and time taking calculation will be here
return true;
}
private bool Analyze()
{
//Some complex and time taking calculation will be here
return true;
}
private bool SomeToDo()
{
//Some complex and time taking calculation will be here
return true;
}
private bool Save()
{
//Some complex and time taking calculation will be here
return true;
}
}
You need to remember that normal async / await will still be performed on the UI thread.
So to be sure that a real long action is pushed to a background thread, you need to wrap it in Task.Run... like Task.Run(() => Task.WhenAll(tasks));
To complete the question a bit more ( seeing the other answer available ), Task.Run usage is not something to take lightly. It all depends on what sort of code needs to be wrapped.
There is a good write up series on this up on the blog of Stephen Cleary here http://blog.stephencleary.com/2013/11/taskrun-etiquette-examples-even-in.html so take some time to go through this and see what fits your project.
Or look here for some other details from Stephen https://stackoverflow.com/a/18015586
The problem that you have is that StartWork claims to be asynchronous, and yet it isn't. It does all of it's work synchronously.
Marking a method as async doesn't make it asynchronous. it just allows you to use the await keyword from within that method. If you perform long running synchronous operations from an async method then that method is still going to be doing that work synchronously.
There are really two approaches to take here. If there are some number of the things done in StartWork that really are inherently asynchronous, then you need to wrap whatever synchronous CPU bound work you have in calls to Task.Run so that the synchronous work that you have can be done asynchronously in a thread pool thread.
If there is no inherently asynchronous operations you have to do in StartWork then make the method clearly synchronous. Have it return a boolean, not a Task, and adjust the name to reflect the fact that it is synchronous. Then have the caller that calls it use Task.Run to do that whole operation on a thread pool thread asynchronously.
Having StartWork falsely claim to be asynchronous, and then still using Task.Run to do the purportedly asynchronous work in another thread is going to be extremely confusing to other readers of your code, as there should be no reason to offload an asynchronous method to a non-UI thread.
IMHO, If you are using Async operation you don't need Task.Run() if you have Sync Task and do it asynchronously you need Task.Run()
If you are using normal synchronous process just return Task<T> and use this Task.Run(()) to use background thread to process. See this answer
private async void button1_Click(object sender, EventArgs e)
{
var itemList = new List<string>() { "Field1", "Field2", "Field3" }; // more than 50 items
Task.Run(() => Task.WhenAll(tasks));
}
public class WorkToDo
{
private string id;
public WorkToDo(string id)
{
this.id = id;
}
public async Task<bool> StartWork()
{
var t1 = Calculate();
var t2 = Analyze();
var t3 = SomeToDo();
//Assuming you need to do all this before you save
// so wait for the all.
await Task.WhenAll(t1,t2,t3);
var result = await Save();
return result;
}
private async Task<bool> Calculate()
{
//Some complex and time taking calculation will be here
//Assuming here you have some DoAsync() method
return true;
}
private async Task<bool> Analyze()
{
//Some complex and time taking calculation will be here
return true;
}
private async Task<bool> SomeToDo()
{
//Some complex and time taking calculation will be here
return true;
}
private async Task<bool> Save()
{
//Some complex and time taking calculation will be here
return true;
}
Using WhenAll() has some advantage like propagating all error at once, see this
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.
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.