I've an extension method for WebClient (WP8)
public static Task<string> DownloadStringTask(this WebClient webClient, Uri uri)
{
var tcs = new TaskCompletionSource<string>();
webClient.DownloadStringCompleted += (s, e) =>
{
if (e.Error != null)
{
tcs.TrySetException(e.Error);
}
else if (e.Cancelled)
{
tcs.TrySetCanceled();
}
else
{
tcs.TrySetResult(e.Result);
}
};
webClient.DownloadStringAsync(uri);
return tcs.Task;
}
and the call to this method
public string GetResult()
{
var task = new WebClient().DownloadStringTask(new Uri("http:\\www.foo.com"));
return task.Result;
}
The DownloadStringCompleted is never executed and obviously there is no result, if I press the pause button on VS always is waiting in task.Result.
Any idea?
Thanks in advance.
Is GetResult executed from the main thread? In that case, it may be a deadlock. If I remember correctly, the callback of the WebClient is executed on the main thread, which cannot happen since you're blocking it by calling task.Result.
You have multiple ways to prevent this issue:
Use a HttpWebRequest instead of a WebClient
Call GetResult from another thread
Execute the task asynchronously by using task.ContinueWith instead of directly task.Result
Rewrite your method using async/await keywords
task.Result blocks the executing thread until the result is available. For me it seems that your code just defeats the purpose of making the request asynchronous. As KooKiz mentioned, use some truly asynchronous API to get the result, such as task.ContinueWith or await task.
Related
I am writing below code in WPF. However, it does not run asynchronously. I have commented the line where the code gets blocked. Please let me know where am I doing the mistake.
private async void txtSampleRequest_Click(object sender, RoutedEventArgs e)
{
await DownloadData();
}
async Task<string> DownloadData()
{
string authorization = txtAuthentication.Text;
string cookie = txtCookie.Text;
try
{
var vvv = Enumerable.Range(0, 50);
List<Task> TaskList = new List<Task>();
foreach (int s in vvv)
{
Task LastTask = ZerodhaOperations.MyHttpRequest("", authorization, cookie, "5minute");//Even this method is async method, and I have added dummy Task.Delay(1) to run method asynchronously. Below is the full definition of this class.
TaskList.Add(LastTask);
}
await Task.WhenAll(TaskList); //<------------ Here it stops working asynchronously and blocks UI of application.
MessageBox.Show("DONE");
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
return "";
}
class ZerodhaOperations
{
public static async Task<string> MyHttpRequest(string WEBSERVICE_URL,string authorization, string cookie,string timeFrame)
{
await Task.Delay(1);
if (authorization == "" || cookie == "" || authorization == null || cookie == null)
{
throw new ArgumentException("Aditya Says, No Authorization and cookie has been set");
}
string jsonResponse = "";
WEBSERVICE_URL = "https://kite.zerodha.com/oms/instruments/historical/519937/timeFrame?user_id=YD0744&oi=1&from=2020-04-24&to=2020-04-24";
WEBSERVICE_URL = $"https://kite.zerodha.com/oms/instruments/historical/806401/{timeFrame}?user_id=YD0744&oi=1&from=2020-12-03&to=2020-12-03";
try
{
var webRequest = System.Net.WebRequest.Create(WEBSERVICE_URL);
//ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3;
ServicePointManager.Expect100Continue = true;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls
| SecurityProtocolType.Tls11
| SecurityProtocolType.Tls12
| SecurityProtocolType.Ssl3;
ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
if (webRequest != null)
{
webRequest.Method = "GET";
webRequest.Timeout = 5000;
if (authorization != "")
{
webRequest.Headers.Add("authority", "kite.zerodha.com");
webRequest.Headers.Add("authorization", authorization);
}
webRequest.Headers.Add("cookie", cookie);
webRequest.Headers.Add("method", "GET");
using (System.IO.Stream s = webRequest.GetResponse().GetResponseStream())
{
using (System.IO.StreamReader sr = new System.IO.StreamReader(s))
{
jsonResponse = sr.ReadToEnd();
if (jsonResponse == "")
throw new Exception("Empty Response");
//MessageBox.Show(jsonResponse);
}
}
}
}
catch (Exception ex)
{
if (ex.Message.Contains("Empty Response"))
throw ex;
else
MessageBox.Show(ex.ToString());
}
return jsonResponse;
}
}
The way await works is that it captures a "context" when it asynchronously yields. The details are in the link, but in this case the asynchronous method is running on the WPF UI thread, so it captures a context that will resume running on that UI thread.
So the await Task.Delay(1) is in fact forcing MyHttpRequest to act asynchronously, but it's what happens next that is tripping you up. MyHttpRequest does the await, which captures the UI context and returns an incomplete task. This happens multiple times in DownloadData, which collects the incomplete tasks and then awaits the Task.WhenAll of them. So then DownloadData returns an incomplete task which is awaited by the event handler, which returns control back to the WPF message loop.
Now, what happens next is that those Task.Delay timers fire off almost immediately. So, MyHttpRequest resumes its async method, and since its await captured that UI context, it resumes running on the UI thread. So the await Task.Delay(1) did cause a yield to the WPF message loop, but then practically the very next thing the UI thread has to do is resume those async methods.
And the remainder of those async methods are synchronous, blocking the UI thread.
So, to solve this, you can make the methods truly asynchronous. Delete the await Task.Delay(1) completely and instead replace the synchronous APIs with asynchronous ones (GetResponseAsync, ReadToEndAsync). Or if you want to modernize the code further, replace WebRequest with HttpClient.
Your other option is to keep the code synchronous and just use Task.Run to run the synchronous code on background threads. Again, you would delete the await Task.Delay(1), and this time you would change the method signature to be synchronous. Then you can wrap the call to the (synchronous) MyHttpRequest in a Task.Run, e.g., Task LastTask = Task.Run(() => ZerodhaOperations.MyHttpRequest("", authorization, cookie, "5minute")); The Task.Run solution is less ideal than the asynchronous solution, but it is acceptable if you have a lot of other code that still needs MyHttpRequest to be synchronous for now.
Note that either way, the usage of Task.Delay(1) is wrong. It does not "run [the] method asynchronously". The proper way to run a method asynchronously is to have it call asynchronous APIs and not call blocking APIs.
I want to call a task which itself call a async method which inturn returna bool value.
I want to do something on the basis of that outcome.
I can get the data on outcome.Result.Result but this does not look good and I wish to have the output in outcome.Result.
I can not figure it out.
Can someone please guide.
private void OnValidated(ValidatedIntergrationEvent evt)
{
var outcome=Task.Factory.StartNew(() => mydata.UpdateValidated());
if (outcome.Result.Result)//This work fine but I think I need something to do so that outcome.Result gives my solution.
{ }
else { }
}
public async Task<bool> UpdateValidated()
{
var result= await Mediator.Send(new ValidatedEvent(this));
return result;
}
public async Task<bool> Handle(ValidatedEvent notification, CancellationToken cancellationToken)
{ //dO WORK
// return Task.FromResult(true);
return true;
}
Since UpdateValidated is already asynchronous, you should just call it directly to execute it. Things like Task.Factory.StartNew or Task.Run offer a way to put synchronous tasks on a new thread so that they can run asynchronously. So you should just call it directly:
private void OnValidated(ValidatedIntergrationEvent evt)
{
var outcome = mydata.UpdateValidated()
// Note: this WILL block, regardless of how you call the async function
var result = outcome.Result;
}
You should try to avoid using .Result though, as this will block synchronous functions until the asynchronous result is ready, and may even cause deadlocks. If the OnValidated is a standard event handler, you could make it asynchronous instead and await your task:
private async void OnValidated(ValidatedIntergrationEvent evt)
{
var result = await mydata.UpdateValidated()
}
But this make this event handler fire and forget which can be dangerous. So you should really try to change your code that you are truly running asynchronously when calling asynchronous code.
Finally, note that you can force the asynchronous task onto a separate thread using Task.Run. This is useful when the asynchronous call also does a lot on the CPU:
var outcome = Task.Run(() => mydata.UpdateValidated());
This looks very similar to your Task.Factory.StartNew() call but returns only a Task<bool> instead of your Task<Task<bool>>. This is because Task.Run has an overload that explicitly allows you to call asynchronous methods which makes Task.Run just pass on the result.
I have an async codeblock running on the pageload.
The codes run smoothy until you reach capturevalue method where we create a new task.On executing that code block the await just freezes and then the control doesnt come back seems like the code just went to deadlock
protected void Page_Load(object sender, EventArgs e)
{
try
{
var textvalue = GetTextValueFromTask();
txtbox.Text = textvalue.Result;
string ss = "";
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
private async Task<string> GetTextValueFromTask()
{
string strReturn = await CaptureValue();
return strReturn;
}
private async Task<string> CaptureValue()
{
Thread.Sleep(5000);
Task<string> T = Task.Factory.StartNew<string>(() => "hi");
return await T;
}
Then I made a small change in Capturevalue method.
private async Task<string> CaptureValue()
{
Thread.Sleep(5000);
Task<string> T = Task.Factory.StartNew<string>(() => "hi");
string ss = T.Result;
return await T;
}
Once I made that change it started working normal.What difference did it make on just fetching the result initially. Please help me Iam a newbee to async
The difference is that second time it doesn't happen any "await" because you waited the task yourself, so await doesn't do anything.
I think you missed the await keyword the first time, here:
var textvalue = await GetTextValueFromTask();
Without it your method GetTextValueFromTask runs synchronously, then it comes into CaptureValue method where await occurs. But the default behaviour of the await is that it tries to capture synchronization context where it was called and to continue the rest of the method in that context, in your example it is WPF synchronization context, which does not allow more than one thread to execute at once. But the continuation cannot proceed, because context is already used by await mechanism.
So, one more time. There is one thread (UI thread), that executes your code up to the last await, which is return await T;, then it yields back to the caller - GetTextValueFromTask, and again to the Page_Load when it gets blocked, because initially you called GetTextValueFromTask synchronously (without await). After that, your operation T completes, and your code tries to continue executing using the initial synchronization context, the WPF one. But it can't, because it is already waiting in the Page_Load.
The link in the comments describes the situation in more detail.
Also consider not using Thread.Sleep in async/await scenarios, because it kills all the "asynchronous" nature of the code. Further reading: link.
Another general piece of advice, which is not directly applicable to your source code, is not to use Task.Factory.StartNew, but rather use Task.Run. Explanation here.
Please use Task.Run() instead of Task.Factory.StartNew()
var T = Task.Run(() => "hi");
It's up to Task.Run to decide how to handle this task.
Also please use .ConfigureAwait(false) in your await calls that do not requires the continuation being done in the awaiter thread context.
I'm still getting up to speed with async & multi threading. I'm trying to monitor when the Task I Start is still running (to show in a UI). However it's indicating that it is RanToCompletion earlier than I want, when it hits an await, even when I consider its Status as still Running.
Here is the sample I'm doing. It all seems to be centred around the await's. When it hits an await, it is then marked as RanToCompletion.
I want to keep track of the main Task which starts it all, in a way which indicates to me that it is still running all the way to the end and only RanToCompletion when it is all done, including the repo call and the WhenAll.
How can I change this to get the feedback I want about the tskProdSeeding task status?
My Console application Main method calls this:
Task tskProdSeeding;
tskProdSeeding = Task.Factory.StartNew(SeedingProd, _cts.Token);
Which the runs this:
private async void SeedingProd(object state)
{
var token = (CancellationToken)state;
while (!token.IsCancellationRequested)
{
int totalSeeded = 0;
var codesToSeed = await _myRepository.All().ToListAsync(token);
await Task.WhenAll(Task.Run(async () =>
{
foreach (var code in codesToSeed)
{
if (!token.IsCancellationRequested)
{
try
{
int seedCountByCode = await _myManager.SeedDataFromLive(code);
totalSeeded += seedCountByCode;
}
catch (Exception ex)
{
_logger.InfoFormat(ex.ToString());
}
}
}
}, token));
Thread.Sleep(30000);
}
}
If you use async void the outer task can't tell when the task is finished, you need to use async Task instead.
Second, once you do switch to async Task, Task.Factory.StartNew can't handle functions that return a Task, you need to switch to Task.Run(
tskProdSeeding = Task.Run(() => SeedingProd(_cts.Token), _cts.Token);
Once you do both of those changes you will be able to await or do a .Wait() on tskProdSeeding and it will properly wait till all the work is done before continuing.
Please read "Async/Await - Best Practices in Asynchronous Programming" to learn more about not doing async void.
Please read "StartNew is Dangerous" to learn more about why you should not be using StartNew the way you are using it.
P.S. In SeedingProd you should switch it to use await Task.Delay(30000); insetad of Thread.Sleep(30000);, you will then not tie up a thread while it waits. If you do this you likely could drop the
tskProdSeeding = Task.Run(() => SeedingProd(_cts.Token), _cts.Token);
and just make it
tskProdSeeding = SeedingProd(_cts.Token);
because the function no-longer has a blocking call inside of it.
I'm not convinced that you need a second thread (Task.Run or StartNew) at all. It looks like the bulk of the work is I/O-bound and if you're doing it asynchronously and using Task.Delay instead of Thread.Sleep, then there is no thread consumed by those operations and your UI shouldn't freeze. The first thing anyone new to async needs to understand is that it's not the same thing as multithreading. The latter is all about consuming more threads, the former is all about consuming fewer. Focus on eliminating the blocking and you shouldn't need a second thread.
As others have noted, SeedingProd needs to return a Task, not void, so you can observe its completion. I believe your method can be reduced to this:
private async Task SeedingProd(CancellationToken token)
{
while (!token.IsCancellationRequested)
{
int totalSeeded = 0;
var codesToSeed = await _myRepository.All().ToListAsync(token);
foreach (var code in codesToSeed)
{
if (token.IsCancellationRequested)
return;
try
{
int seedCountByCode = await _myManager.SeedDataFromLive(code);
totalSeeded += seedCountByCode;
}
catch (Exception ex)
{
_logger.InfoFormat(ex.ToString());
}
}
await Task.Dealy(30000);
}
}
Then simply call the method, without awaiting it, and you'll have your task.
Task mainTask = SeedingProd(token);
When you specify async on a method, it compiles into a state machine with a Task, so SeedingProd does not run synchronously, but acts as a Task even if returns void. So when you call Task.Factory.StartNew(SeedingProd) you start a task that kick off another task - that's why the first one finishes immediately before the second one. All you have to do is add the Task return parameter instead of void:
private async Task SeedingProdAsync(CancellationToken ct)
{
...
}
and call it as simply as this:
Task tskProdSeeding = SeedingProdAsync(_cts.Token);
I have a very strange problem. My WebClient.DownloadDataCompleted doesn't fire most of the time.
I am using this class:
public class ParallelFilesDownloader
{
public Task DownloadFilesAsync(IEnumerable<Tuple<Uri, Stream>> files, CancellationToken cancellationToken)
{
var localFiles = files.ToArray();
var tcs = new TaskCompletionSource<object>();
var clients = new List<WebClient>();
cancellationToken.Register(
() =>
{
// Break point here
foreach (var wc in clients.Where(x => x != null))
wc.CancelAsync();
});
var syncRoot = new object();
var count = 0;
foreach (var file in localFiles)
{
var client = new WebClient();
client.DownloadDataCompleted += (s, args) =>
{
// Break point here
if (args.Cancelled)
tcs.TrySetCanceled();
else if (args.Error != null)
tcs.TrySetException(args.Error);
else
{
var stream = (Stream)args.UserState;
stream.Write(args.Result, 0, args.Result.Length);
lock (syncRoot)
{
count++;
if (count == localFiles.Length)
tcs.TrySetResult(null);
}
}
};
clients.Add(client);
client.DownloadDataAsync(file.Item1, file.Item2);
}
return tcs.Task;
}
}
And when I am calling DownloadFilesAsync in LINQPad in isolation, DownloadDataCompleted is called after half a second or so, as expected.
However, in my real application, it simply doesn't fire and the code that waits for it to finish simply is stuck. I have two break points as indicated by the comments. None of them is hit.
Ah, but sometimes, it does fire. Same URL, same code, just a new debug session. No pattern at all.
I checked the available threads from the thread pool: workerThreads > 30k, completionPortThreads = 999.
I added a sleep of 10 seconds before the return and checked after the sleep that my web clients haven't been garbage collected and that my event handler is still attached.
Now, I ran out of ideas to trouble shoot this.
What else could cause this strange behaviour?
From the comments:
Somewhere later, there is a Task.WaitAll which waits for this and other tasks. However, (1) I fail to see why this would affect the async download - please elaborate - and (2) the problem doesn't disappear, when I add the sleep and as such, Task.WaitAll will not be called
It seems that you have a deadlock caused by Task.WaitAll. I can explain it throughly here:
When you await an async method that returns a Task or a Task<T>, there is an implicit capture of the SynchronizationContext by the TaskAwaitable being generated by the Task.GetAwaiter method.
Once that sync context is in place and the async method call completes, the TaskAwaitable attempts to marshal the continuation (which is basically the rest of the method calls after the first await keyword) onto the SynchronizationContext (using SynchronizationContext.Post) which was previously captured. If the calling thread is blocked, waiting on that same method to finish, you have a deadlock.
When you call Task.WaitAll, you block until all Tasks are complete, this will make marshaling back to the original context impossible, and basically deadlock.
Instead of using Task.WaitAll, use await Task.WhenAll.
Based on the comments, not an ideal answer but you can temporarily change the sync context before and after the foreach:
var syncContext = SynchronizationContext.Current;
SynchronizationContext.SetSynchronizationContext(null);
foreach (var file in localFiles)
{
...
}
SynchronizationContext.SetSynchronizationContext(syncContext);