Note: I'm using C# in Unity, that means version .NET 3.5, so I cannot use await or async keyword..
What will happen to using statement when I put a method in it which works asynchronously?
using (WebClient wc = new WebClient()) {
wc.DownloadFileAsync(urlUri, outputFile);
}
SomeMethod1();
SomeMethod2();
As you know, after the method DownloadFileAsync() is called, SomeMethod1() will be called which is out of the using block while DownloadFileAsync() is still working. So now I'm really confused what would happen to the using statement and the asynchronous method in this case.
Would Dispose() of wc be called at the right time without any problems?
If not, how do I correct this example?
From the comments:
Then how do I avoid this? Just add await keyword?
No, you can't just do that. (And that's why the previously proposed duplicate question was not in fact a duplicate…your scenario is subtly different.) You will need to delay the dispose until the download has completed, but this is complicated by your need to execute two more program statements (at least…it's impossible to know for sure without a good, minimal, complete code example).
I do think you should switch to the awaitable WebClient.DownloadFileTaskAsync() method, as this will at least simplify the implementation, making it simple to retain the using statement.
You can address the other part of the problem by capturing the returned Task object and not awaiting it until after your other program statements have executed:
using (WebClient wc = new WebClient()) {
Task task = wc.DownloadFileTaskAsync(urlUri, outputFile);
SomeMethod1();
SomeMethod2();
await task;
}
In this way, the download can be started, your other two methods called, and then the code will wait for the completion of the download. Only when it's completed will the using block then be exited, allowing the WebClient object to be disposed.
Of course, in your current implementation you undoubtedly are handling an appropriate DownloadXXXCompleted event. If you want, you can continue using the object that way. But IMHO once you have switched over to using await, it's much better to just put after the await the code that needs to execute on the completion of the operation. This keeps all of the code relevant to the operation in one place and simplifies the implementation.
If for some reason you can't use await, then you will have to use some alternate mechanism for delaying the dispose of the WebClient. Some approaches will allow you to continue to use using, others will require that you call Dispose() in the DownloadXXXCompleted event handler. Without a more complete code example, and a clear explanation for why await is not suitable, it would not be possible to say for sure what the best alternative would be.
EDIT:
Since you've confirmed that you don't have access to await in the current code, here are a couple of other options compatible with older code…
One possibility is to just wait in the same thread after starting the operation:
using (WebClient wc = new WebClient()) {
object waitObject = new object();
lock (waitObject)
{
wc.DownloadFileCompleted += (sender, e) =>
{
lock (waitObject) Monitor.Pulse(waitObject);
};
wc.DownloadFileAsync(urlUri, outputFile);
SomeMethod1();
SomeMethod2();
Monitor.Wait(waitObject);
}
}
(Note: one can use any suitable synchronization above, such as ManualResetEvent, CountdownEvent, or even Semaphore and/or "slim" equivalents. I use Monitor simply due to its simplicity and efficiency, and take as granted readers can adjust to accommodate their preferred means of synchronization. One obvious reason one might prefer something other than Monitor is that the other types of synchronization techniques won't run the risk of having the DownloadFileCompleted event handler itself block waiting on the SomeMethod1() and SomeMethod2() methods to complete. Whether this is important depends of course on how long those method calls would take as compared to the file download.)
The above will, however, block the current thread. In some cases this may be fine, but most often the operation is being initiated in the UI thread, and that thread should not be blocked for the duration of the operation. In that case, you will want to forego using altogether and just call Dispose() from the completion event handler:
WebClient wc = new WebClient();
wc.DownloadFileCompleted += (sender, e) =>
{
wc.Dispose();
};
wc.DownloadFileAsync(urlUri, outputFile);
SomeMethod1();
SomeMethod2();
The System.Net.WebClient provides the event DownloadFileCompleted. You could add a handler for that event and dispose of the client at that time.
Related
I have these methods in a class
public async Task GetCompanies(int requestDuration, long startTimepoint)
{
_requestDuration = requestDuration;
_startTimepoint = startTimepoint;
Thread thread = new Thread(new ThreadStart(Test));
// This line doesnt compile - No overload for GetCompaniesApi matches delegate ThreadStart
Thread thread2 = new Thread(new ThreadStart(GetCompaniesApi));
}
public void Test()
{
}
public async Task GetCompaniesApi (int requestDuration, long? startTimepoint)
{
// code removed as not relevant
}
So my question is how can I run a method that is async in a different thread, I don't really know what "No overload for GetCompaniesApi matches delegate ThreadStart" means, or what I need to change.
EDIT
If I just explain fully what i'm trying to do that might be better than the more specific question I asked at the start.
Basically I want to call a HTTP GET request which is streaming, as in it never ends, so I want to force the HTTP GET request to end after X seconds and whatever we have got from the response body at that point will be it.
So in order to try and do this I thought i'd run that HTTP GET request in a separate thread, then sleep the main thread, then somehow get the other thread to stop. I don't see how its possible to use cancellation tokens as the thread is stuck on line "await _streamToReadFrom.CopyToAsync(streamToWriteTo);" all the time.
public async Task GetCompanies(int requestDuration, long startTimepoint)
{
Task task = Task.Run(() => { GetCompaniesApi(requestDuration, startTimepoint); });
Thread.Sleep(requestDuration * 1000);
// Is it now possible to cancel task?
}
public async Task GetCompaniesApi (int requestDuration, long? startTimepoint)
{
string url = $"https://stream.companieshouse.gov.uk/companies?timepoint={startTimepoint}";
using (HttpResponseMessage response = await _httpClient.GetAsync(url, HttpCompletionOption.ResponseHeadersRead))
using (_streamToReadFrom = await response.Content.ReadAsStreamAsync())
{
string fileToWriteTo = Path.GetTempFileName();
using (Stream streamToWriteTo = System.IO.File.Open(fileToWriteTo, FileMode.Create))
{
await _streamToReadFrom.CopyToAsync(streamToWriteTo);
}
}
}
ThreadStart is a delegate representing parameterless method with void return value (so it it not async aware, i.e. the tread will not wait for task completion), while your method requires 2 parameters to be passed so from purely technical standpoint you can do something like new ThreadStart(() => GetCompaniesApi(1,2)), or just new Thread(() => GetCompaniesApi(1, 2)) (compiler will create the delegate for you). But you should not.
In modern .NET rarely there is need to create threads directly, just use Task.Run to schedule your async method on the thread pool (do not forget to provide the parameters):
await Task.Run(() => Test());
For async method - just invoke it:
var result = await GetCompaniesApi(someInt, someNullableLong);
If for some reason it is not actually async then better fix the method itself, but if needed you can wrap it into Task.Run too.
I think the question reveals a potential misunderstanding of multi threading and async.
The main purpose of async is to hide the latency of IO operations, like network or disk access. That helps reducing resource usage, and keeping the UI responsive.
Using background threads are mostly for hiding the latency of computations. For example if you are doing some slow image processing task. In that case you typically use Task.Run to execute a synchronous method, and await the result. Just make sure the method is thread safe.
While there are cases that mix these types of work and where you need to combine both methods, it is not that common. From your code I would guess your work is mostly IO related, so you should probably not use any backgrounds threads. Note that some libraries lie about being asynchronous, i.e. methods that return a task, but will still block. In that treating the method as a synchronous thread and use Task.Run to execute it might be warranted.
Also keep in mind that multi threaded programming is difficult. It introduces a great number of new types of faults, and most faults will not be caught by the compiler, and many are spurious and difficult to reproduce. So you really need to be aware of the dangers and know how to correctly use locks and other forms of synchronization.
I managed to find some answers to similar questions posted around the internet, but no one of them explained it satisfying enough to make me understand the difference in the code below.
I am aware that await, unlike .Result, doesn't block calling thread. But what if we're trying to access this property from a task, which doesn't block it anyway?
For instance, is there any difference between this
public static Task PrintPageAsync(string url)
{
return Task.Run(() =>
{
WebRequest webRequest = WebRequest.Create(url);
WebResponse response = webRequest.GetResponseAsync().Result;
using (StreamReader reader = new StreamReader(response.GetResponseStream()))
{
string text = reader.ReadToEndAsync().Result;
Console.WriteLine(text);
}
});
}
and this
public static async Task PrintPageAsync(string url)
{
WebRequest webRequest = WebRequest.Create(url);
WebResponse response = await webRequest.GetResponseAsync();
using (StreamReader reader = new StreamReader(response.GetResponseStream()))
{
string text = await reader.ReadToEndAsync();
Console.WriteLine(text);
}
}
.Result will execute your code synchronously, i.e. you're disregarding the very essence of the Task and entire TPL standing behind it. await, as it says, is a marker for the compiler to rewrite your method in a good-old "callback" fashion (a-ka typical JavaScript), which is asynchronous way to complete exactly the same computation.
Simpler: you should prefer await over .Result whenever possible.
Since the first example starts a new task on a threadpool thread, calling asynchronous methods is unnecessary, when there are equivalent synchronous methods. It does not have any benefit, it just needlessly add some overhead involved in managing asynchronous tasks. Just use .GetResponse() instead of .GetResponseAsync().Result and .ReadToEnd() instead of .ReadToEndAsync().Result.
await, unlike .Result, doesn't block calling thread
This is not always true. Awaited methods can execute (partially or completely) synchronously, if they decide to do so.
For instance, is there any difference?
There are a bunch of differences between the two examples. Although they may be insignificant in certain contexts, they can be crucial in another:
AggregateException
When exception occurs in a task or task is cancelled, calling Task.Result will wrap exception in an AggregateException. Contrary, awaiting this task will throw the original exception. So you must be careful when catching specific exception.
Thread
In the first example, whole method will execute on the same (threadpool) thread. The second example can execute on several different threads, depending on the current SynchronizationContext. Code sensitive to thread-affinity should be avoided.
SynchronizationContext
First exapmple will execute without SynchronizationContext, while the second will restore original SynchronizationContext after each await. For console applications, this doesn't matter. But in WPF or WinForms applications, UI elements can be accessed only from corresponding synchronization context.
Asynchronous execution
In the first example, PrintPageAsync will return immediatelly after new task is queued for execution, while the second will execute synchronously up to the first await (or possibly even after that). This can have severe impact on GUI responsivnes, especially when async method uses WebRequest, because GetResponseAsync() method performs DNS resolution synchronously (see How to create HttpWebRequest without interrupting async/await?). So wrapping code in a Task.Run() is recomended, when method that uses WebRequest is called from UI thread.
I'm trying to understand how and when to use async programming and got to I/O bound operations, but I don't understand them. I want to implement them from scratch. How can I do that?
Consider the example below which is synchronous:
private void DownloadBigImage() {
var url = "https://cosmos-magazine.imgix.net/file/spina/photo/14402/180322-Steve-Full.jpg";
new WebClient().DownloadFile(url, "image.jpg");
}
How do I implement the async version by only having the normal synchronous method DownloadBigImage without using Task.Run since that will use a thread from the thread pool only for waiting - that's just being wasteful!
Also do not use the special method that's already async! This is the purpose of this question: how do I make it myself without relying on methods which are already async? So, NO things like:
await new WebClient().DownloadFileTaskAsync(url, "image.jpg");
Examples and documentation available are very lacking in this regard. I found only this:
https://learn.microsoft.com/en-us/dotnet/standard/async-in-depth
which says:
The call to GetStringAsync() calls through lower-level .NET libraries (perhaps calling other async methods) until it reaches a P/Invoke interop call into a native networking library. The native library may subsequently call into a System API call (such as write() to a socket on Linux). A task object will be created at the native/managed boundary, possibly using TaskCompletionSource. The task object will be passed up through the layers, possibly operated on or directly returned, eventually returned to the initial caller.
Basically I have to use a "P/Invoke interop call into a native networking library"... but how?
This is a great question which really isn't explained well in most texts about C# and async.
I searched for this for ages thinking I could and should maybe be implementing my own async I/O methods. If a method/library I was using didn't have async methods I thought I should somehow wrap these functions in code that made them asynchronous. It turns out that this isn't really feasible for most programmers. Yes, you can spawn a new thread using Thread.Start(() => {...}) and that does make your code asynchronous, but it also creates a new thread which is an expensive overhead for asynchronous operations. It can certainly free up your UI thread to ensure your app stays responsive, but it doesn't create a truly async operation the way that HttpClient.GetAsync() is a truly asynchronous operation.
This is because async methods in the .net libraries use something called "standard P/Invoke asynchronous I/O system in .NET" to call low level OS code that doesn't require a dedicated CPU thread while doing outbound IO (networking or storage). It actually doesn't dedicate a thread to its work and signals the .net runtime when it's done doing its stuff.
I'm not familiar with the details but this knowledge is enough to free me from trying to implement async I/O and make me focus on using the async methods already present in the .net libraries (such as HttpClient.GetAsync()). More interesting info can be found here (Microsoft async deep dive) and a nice description by Stephen Cleary here
I think this is a very interesting question and a fun learning exercise.
Fundamentally, you cannot use any existing API that is synchronous. Once it's synchronous there is no way to turn it truly asynchronous. You correctly identified that Task.Run and it's equivalents are not a solution.
If you refuse to call any async .NET API then you need to use PInvoke to call native APIs. This means that you need to call the WinHTTP API or use sockets directly. This is possible but I don't have the experience to guide you.
Rather, you can use async managed sockets to implement an async HTTP download.
Start with the synchronous code (this is a raw sketch):
using (var s = new Socket(...))
{
s.Connect(...);
s.Send(GetHttpRequestBytes());
var response = new StreamReader(new NetworkStream(s)).ReadToEnd();
}
This very roughly gets you an HTTP response as a string.
You can easily make this truly async by using await.
using (var s = new Socket(...))
{
await s.ConnectAsync(...);
await s.SendAsync(GetHttpRequestBytes());
var response = await new StreamReader(new NetworkStream(s)).ReadToEndAsync();
}
If you consider await cheating with respect to your exercise goals you would need to write this using callbacks. This is awful so I'm just going to write the connect part:
var s = new Socket(...)
s.BeginConnect(..., ar => {
//perform next steps here
}, null);
Again, this code is very raw but it shows the principle. Instead of waiting for an IO to complete (which happens implicitly inside of Connect) you register a callback that is called when the IO is done. That way your main thread continues to run. This turns your code into spaghetti.
You need to write safe disposal with callbacks. This is a problem because exception handling cannot span callbacks. Also, you likely need to write a read loop if you don't want to rely on the framework to do that. Async loops can be mind bending.
TLDR: Generally you can by using TaskCompletionSource.
If you only have blocking calls available then you cannot do this. But usually there are "old" asynchronous methods that do not use async nor Task, but rely instead on callbacks. In that case you can use a TaskCompletionSource to both create a Task that can be returned, and use it to set the Task to completed when the callback returns.
Example using the old .Net Framework 3.0 methods in WebClient (but programmed in later .Net that has Task):
public Task DownloadCallbackToAsync(string url, string filename)
{
using (var client = new WebClient())
{
TaskCompletionSource taskCreator = new TaskCompletionSource();
client.DownloadFileCompleted += (sender, args) => taskCreator.SetResult();
client.DownloadFileAsync(url, filename);
return taskCreator.Task;
}
}
Here you will imidiately initiate the call and return a Task. If you await the Task in the calling method you will not continue until the callback (DownloadFileCompleted) has occurred.
Note that this method itself is not async as it does not need to await a Task.
Create a new task that executes the synchronous code. The task will be executed by a thread of the threadpool.
private async Task DownloadBigImage()
{
await Task.Run(()=>
{
var url = "https://cosmos-magazine.imgix.net/file/spina/photo/14402/180322-Steve-Full.jpg";
new WebClient().DownloadFile(url, "image.jpg");
});
}
I would like to read data from a stream (serial, tcp, whatever) asynchronously and trigger events to notify other components.
Following is pseudo code, assuming "stream" is a valid stream.
public class Reader {
private _stream;
private _buffer = new bytes[4096];
public event Action<byte[], int> DataRecieved;
public async void StartReading() {
while (true) {
var nbytes = await _stream.ReadAsync(_buffer, 0, _buffer.Length);
if (nbytes == 0)
return;
var handlers = DataRecieved;
if (handlers != null)
DataRecieved(_buffer, nbytes);
}
}
}
And the caller part:
var r = new Reader();
r.OnDataRecieved += myHandler;
r.StartReading();
I'm not sure doing something like this is a good idea. I read that using asynchonous void functions is not a good idea, but here I don't want caller to wait for the result, I want to notify it when some data is available.
What's the good way to do something like that ?
void async is only considered to be used for GUI event handlers. In WinForms, events have all delegate-types of type void. Usually, you want, when using async , notify your caller when you have finished - in an asynchronous way. The .NET message-loop is considered the exception here, since you have no different possibility to use async.
In your case, the async/await keywords won't make much sense. I'd recommend to invoke your method using a Task or the ThreadPool (or BackgroundWorker).
You do not have a long running task on which you want to react in a asynchronous manner, but a parallel background-task, which should be used as such.
The idea of async/await is that the caller of a method continues after the method invocation and may execute code inside the method behind an await later. But that requires you to use await in the calling-method, which would block your main-thread.
Long story short: You have no other chance as using a second thread and use thread-synchronization.
Invoke is nothing else as placing a delegate in a queue which the message-loop reads and executes. In your case, you could do something similar: Take the read data, like the byte[] and put that in a queue (via the event). And whenever your main-thread desires to do some work, he grabs an item from the queue.
That is one option. The best solution for this issue depends strongly on your application, and as far as you didn't tell us more details about the design, I can't recommend the best way. But async/await won't be it. Definitely.
Make the method return Task to avoid async void. You can ignore that task if you want but eventually you probably want to wait for it to complete.
Also handle errors. Right now they are thrown away and the reading stops silently. You will never find bugs this way.
Wrap everything in Task.Run to make sure that this async method really runs completely asynchronously. Right now if each await completes right away this method will never return or not return in a long time. Don't risk that. Alternatively you can place await Task.Yield(); at the first line of the method.
I need to make async request to web resource and use example from this page (link to full example):
HttpWebRequest myHttpWebRequest= (HttpWebRequest)WebRequest.Create("http://www.contoso.com");
RequestState myRequestState = new RequestState();
myRequestState.request = myHttpWebRequest;
// Start the asynchronous request.
IAsyncResult result=
(IAsyncResult) myHttpWebRequest.BeginGetResponse(new AsyncCallback(RespCallback),myRequestState);
But when I am testing the application the execution freeze(on 2-3 sec) on the last line of this code (i can watch it using debugger).
Why? Is it my mistake or it is a standard behaviour of the function?
You can try, I m sure thats better
private void StartWebRequest(string url)
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.BeginGetResponse(new AsyncCallback(FinishWebRequest), request);
}
private void FinishWebRequest(IAsyncResult result)
{
HttpWebResponse response = (result.AsyncState as HttpWebRequest).EndGetResponse(result) as HttpWebResponse;
}
Because of chross thread of textbox'value,But this is wpf application i will retag this, btw you can use webclient like
private void tbWord_TextChanged(object sender, TextChangedEventArgs e)
{
WebClient wc = new WebClient();
wc.DownloadStringCompleted += HttpsCompleted;
wc.DownloadStringAsync(new Uri("http://en.wikipedia.org/w/api.php?action=opensearch&search=" + tbWord.Text));
}
private void HttpsCompleted(object sender, DownloadStringCompletedEventArgs e)
{
if (e.Error == null)
{
//do what ever
//with using e.Result
}
}
It's the standard behaviour.
From the documentation on HttpWebRequest.BeginGetResponse Method:
The BeginGetResponse method requires some synchronous setup tasks to complete (DNS resolution, proxy detection, and TCP socket connection, for example) before this method becomes asynchronous. [...]
it might take considerable time (up to several minutes depending on network settings) to complete the initial synchronous setup tasks before an exception for an error is thrown or the method succeeds.
To avoid waiting for the setup, you can use
HttpWebRequest.BeginGetRequestStream Method
but be aware that:
Your application cannot mix synchronous and asynchronous methods for a particular request. If you call the BeginGetRequestStream method, you must use the BeginGetResponse method to retrieve the response.
The response occurs on a separate thread. Winforms are not multi-thread safe, so you're going to have to dispatch the call on the same thread as the form.
You can do this using the internal message loop of the window. Fortunately, .NET provides a way to do this. You can use the control's Invoke or BeginInvoke methods to do this. The former blocks the current thread until the UI thread completes the invoked method. The later does so asynchronously. Unless there is cleanup to do, you can use the latter in order to "fire and forget"
For this to work either way, you'll need to create a method that gets invoked by BeginInvoke, and you'll need a delegate to point to that method.
See Control.Invoke and Control.BeginInvoke in the MSDN for more details.
There's a sample at this link: https://msdn.microsoft.com/en-us/library/zyzhdc6b(v=vs.110).aspx
Update: As I'm browsing my profile because I forgot i had an account here - i noticed this and I should add: Anything past 3.5 or when they significantly changed the asynchronous threading model here is out of my wheelhouse. I'm out professionally, and while I still love the craft, I don't follow every advancement. What I can tell you is this should work in all versions of .NET but it may not be the absolute pinnacle of performance 4.0 and beyond or on Mono/Winforms-emulation if that's still around. On the bright side, any hit usually won't be bad outside server apps, and even inside if the threadpool is doing its job. So don't focus optimization efforts here in most cases, and it's more likely to work on "stripped down" platforms you see running things like C# mobile packages although I'd have to look to be sure and most don't run winforms but some spin message loops and this works there too. Basically to bottom line, it's not the "best answer" for the newest platforms in every last case. But it might be more portable in the right case. If that helps one person avoid making a design error, then it was worth the time I took to write this. =)
You can use BackgroundWorker add do the whole thing in DoWork