C# async await for pooling - c#

I need to do some WebRequest to a certain endpoint every 2 seconds. I tried to do it with a Timer, the problem is that every call to the callback function is creating a different Thread and I'm havind some concurrence problems. So I decided to change my implementation and I was thinking about using a background worker with a sleep of two seconds inside or using async await but I don't see the advantages of using async await. Any advice? thank you.
This is the code that I will reimplement.
private void InitTimer()
{
TimerCallback callback = TimerCallbackFunction;
m_timer = new Timer(callback, null, 0, m_interval);
}
private void TimerCallbackFunction(Object info)
{
Thread.CurrentThread.Name = "Requester thread ";
m_object = GetMyObject();
}
public MyObject GetMyObject()
{
MyObject myobject = new MyObject();
try
{
MemoryStream responseInMemory = CreateWebRequest(m_host, ENDPOINT);
XmlSerializer xmlSerializer = new XmlSerializer(typeof(MyObject));
myObject = (MyObject) xmlSerializer.Deserialize(responseInMemory);
}
catch (InvalidOperationException ex)
{
m_logger.WriteError("Error getting MyObject: ", ex);
throw new XmlException();
}
return myObject;
}
private MemoryStream CreateWebRequest(string host, string endpoint)
{
WebRequest request = WebRequest.Create(host + endpoint);
using (var response = request.GetResponse())
{
return (MemoryStream) response.GetResponseStream();
}
}
EDIT: I have read this SO thread Async/await vs BackgroundWorker

async await is also concurrence. If you have concurrence problems and you want your application to have only one thread, you should avoid using async await.
However the best way to do WebRequest is to use async await, which does not block the main UI thread.
Use the bellow method, it will not block anything and it is recommended by Microsoft. https://msdn.microsoft.com/en-us/library/86wf6409(v=vs.110).aspx
private async Task<MemoryStream> CreateWebRequest(string host, string endpoint)
{
WebRequest request = WebRequest.Create(host + endpoint);
using (var response = await request.GetResponseAsync())
{
return (MemoryStream)response.GetResponseStream();
}
}

You don't mention what the concurrency problems are. It may be that the request takes so long that the next one starts before the previous one finishes. It could also be that the callback replaces the value in my_Object while readers are accessing it.
You can easily make a request every X seconds, asynchronously and without blocking, by using Task.Delay, eg:
ConcurrentQueue<MyObject> m_Responses=new ConcurrentQueue<MyObject>();
public async Task MyPollMethod(int interval)
{
while(...)
{
var result=await SomeAsyncCall();
m_Responses.Enqueue(result);
await Task.Delay(interval);
}
}
This will result in a polling call X seconds after the last one finishes.
It also avoids concurrency issues by storing the result in a concurrent queue instead of replacing the old value, perhaps while someone else was reading int.
Consumers of MyObject would call Dequeue to retrieve MyObject instances in the order they were received.
You could use the ConcurrentQueue to fix the current code too:
private void TimerCallbackFunction(Object info)
{
Thread.CurrentThread.Name = "Requester thread ";
var result=GetMyObject();
m_Responses.Enqueue(result);
}
or
private async void TimerCallbackFunction(Object info)
{
Thread.CurrentThread.Name = "Requester thread ";
var result=await GetMyObjectAsync();
m_Responses.Enqueue(result);
}
if you want to change your GetObject method to work asynchronously.
Since your request seems to take a long time, it's a good idea to make it asynchronous and avoid blocking the timer's ThreadPool thread while waiting for a network response.

Related

Using MessageBox when part of an await has ConfigureAwait false

Reading Stephen Cleary take on not blocking on Async code I write something like this
public static async Task<JObject> GetJsonAsync(Uri uri)
{
using (var client = new HttpClient())
{
var jsonString = await client.GetStringAsync(uri).ConfigureAwait(false);
return JObject.Parse(jsonString);
}
}
public async void Button1_Click(...)
{
var json = await GetJsonAsync(...);
textBox1.Text=json;
}
so far so good, I understand that after the ConfigureAwait the method is going to continue running on a different context after GetStringAsync returns.
but what about if I want to use something like MessageBox (which is UI) like this
public static async Task<JObject> GetJsonAsync(Uri uri)
{
if(someValue<MAXVALUE)
{
using (var client = new HttpClient())
{
//var jsonString = await client.GetStringAsync(uri); //starts the REST request
var jsonString = await client.GetStringAsync(uri).ConfigureAwait(false);
return JObject.Parse(jsonString);
}
}
else
{
MessageBox.Show("The parameter someValue is too big!");
}
}
can I do this?
Even more complicated, how about this?
public static async Task<JObject> GetJsonAsync(Uri uri)
{
if(someValue<MAXVALUE)
{
try{
using (var client = new HttpClient())
{
//var jsonString = await client.GetStringAsync(uri); //starts the REST request
var jsonString = await client.GetStringAsync(uri).ConfigureAwait(false);
return JObject.Parse(jsonString);
}
}
catch(Exception ex)
{
MessageBox.Show("An Exception was raised!");
}
}
else
{
MessageBox.Show("The parameter someValue is too big!");
}
}
Can I do this?
Now, I am thinking perhaps all the message boxes should be called outside GetJsonAync as good design, but my question is can the above thing be done?
can I do this? [use a MessageBox]
Yes, but mainly because it has nothing to do with async/await or threading.
MessageBox.Show() is special, it is a static method and is documented as thread-safe.
You can show a MessageBox from any thread, any time.
So maybe it was the wrong example, but you do have MessageBox in the title.
public static async Task<JObject> GetJsonAsync(Uri uri)
{
try{
... // old context
... await client.GetStringAsync(uri).ConfigureAwait(false);
... // new context
}
catch
{
// this might bomb
someLabel.Text = "An Exception was raised!";
}
}
In this example, there could be code paths where the catch runs on the old and other paths where it runs on the new context.
Bottom line is: you don't know and should assume the worst case.
I would not use a Message Box, as it is very limited, and dated.
Also, Pop up's are annoying.
Use your own user control which enables user interaction the way you intend it.
In the context of Winforms / WPF / (and I guess UWP), only a single thread can manipulate the UI. Other threads can issue work to it via a queue of actions which eventually get invoked.
This architecture prevents other threads from constantly poking at the UI, which can make UX very janky (and thread unsafe).
The only way to communicate with it the UI work queue (in Winforms) is via the System.Windows.Form.Controls.BeginInvoke instance method, found on every form and control.
In your case:
public async void Button1_Click(...)
{
var json = await GetJsonAsync(...).ConfigureAwait(false);
BeginInvoke(UpdateTextBox, json);
}
private void UpdateTextBox(string value)
{
textBox1.Text=json;
}

Understanding await and async in .NET

I am working on refactoring code that uses the Bootstrap protocol to update the firmware of several nodes in a machine. The current code looks something like this (pseudo-code):
public void StartUpdate()
{
Sokcet bootpSocket = new Socket():
StateObject bootpState = new StateObject(bootpSocket);
BOOTPReceive(bootpState);
SendMagicPacket();
while (!IsError && !IsUpdateComplete)
{
//wait for BOOTP/Update to finish before returning to caller
}
}
private void BOOTPReceive(object state)
{
bOOTPSocket.BeginReceive(PACKET_DATA, 0, PACKET_DATA.Length, 0, OnBOOTPReceive, state);
}
SendMagicPacket()
{
//create and send magic packet
// this will tell the node to respond with a BOOTPPacket
}
private void OnBOOTPReceive(IAsyncResult result)
{
StateObject state = (StateObject) result.AsyncState;
Socket handler = state.workSocket;
int bytesRcvd = handler.EndReceive(result);
packet = PACKET_DATA;
if(isValidBOOTP(packet))
{
SendBOOTPResponse();
}
else{
BOOTPReceive(); //keep listening for valid bootp response
}
}
private void SendBOOTPResponse()
{
UdpClient udpClient = new UdpClient();
udpClient.BeginSend(packetData, packetData.Length, BROADCAST_IP, (int)UdpPort.BOOTP_CLIENT_PORT, OnBOOTPSend, udpClient);
}
private void OnBOOTPSend(IAsyncResult result)
{
UdpClient udpClient = (UdpClient)result.AsyncState;
int bytesSent = udpClient.EndSend(result);
udpClient.Close();
}
What I want to do is convert this to async-await but still require that I don't return back to the caller right away. How would I go about doing this? Is this possible to do? And would this be the right thing to do since await-async propagates all the way to the top?
Pseudo-code of what I think this would look like:
public void StartUpdate()
{
bool result = await SendMagicPacket();
bool IsError = await BOOTPCommunication(); //Handles all of the BOOTP recieve/sends
//don't return to caller until BOOTPCommunication is completed. How do i do this?
}
You need to wait for the two tasks try the following:
public async Task StartUpdate()
{
var resultTask = SendMagicPacket();
var isErrorTask = BOOTPCommunication(); //Handles all of the BOOTP recieve/sends
await Task.WhenAll(new[]{resultTask, isErrorTask});
//don't return to caller until BOOTPCommunication is completed. How do i do this?
}
//wait for BOOTP/Update to finish before returning to caller
You don't need any async IO at all because you want to wait until all operations are done. I assume you have copied some sample code. Most sample code uses async socket APIs.
Switch everything over to synchronous socket APIs and you're done.
If you want to keep this async for some reason you can indeed switch to await and untangle this code. The pseudo-code you posted looks like a good goal. It forces the surrounding method to be async Task, though.
You can deal with that by making all callers recursively async as well. If you don't need to conserve threads you could block on that task and have a mostly synchronous call chain. At that point you lose all async benefits, though.
Radin was on the right track, but I think what you want is something like this:
You need to wait for the two tasks try the following:
public async Task StartUpdate()
{
var resultTask = SendMagicPacket();
var isErrorTask = BOOTPCommunication(); //Handles all of the BOOTP recieve/sends
Task.WhenAll(new[]{resultTask, isErrorTask}).Wait(); //Wait() will block so that the method doesn't return to the caller until both of the asynchronous tasks complete.
}
What that allows is SendMagicPacket and BOOTPCommunication to both fire simultaneously, but to wait for BOTH to complete. Using that pattern you can fire of N events simultaneously, while using Wait() to wait for all to finish so that the method itself returns synchronously.

C# async HttpWebRequest deadlocking

For few hours I am struggling with async code in C# and I can't really get why is my code deadlocked.
So far I've red many articles and anything ringed the bell for me.
Hope you can help me.
Here is the code I am trying to run.
Main
Task.Run(async () =>
{
Task<EventDetailed[]> events = getDetailedEvents();
await events;
}).Wait();
getDetailedEvents:
static async Task<EventDetailed[]> getDetailedEvents()
{
...
EventDetailed[] result = await LoadDetailedEventsDetailsAsync(evnts).ConfigureAwait(false);
return result;
}
And the core of my problem.
LoadDetailedEventsDetailsAsync
async static Task<EventDetailed[]> LoadDetailedEventsDetailsAsync(Event[] events)
{
List<EventDetailed> detailed = new List<EventDetailed>();
List<Task<WebResponse>> responses = new List<Task<WebResponse>>();
List<Event> tasksWithStream = new List<Event>();
foreach (Event e in events)
{
var httpWebRequest = (HttpWebRequest)WebRequest.Create("http://...");
... some headers etc ...
e.Stream = httpWebRequest.GetRequestStreamAsync();
e.WebRequest = httpWebRequest;
tasksWithStream.Add(e);
}
foreach (var tsk in tasksWithStream)
{
try {
await tsk.Stream.ConfigureAwait(false);
using (var streamWriter = new StreamWriter(tsk.Stream.Result))
{
streamWriter.Write("...");
streamWriter.Flush();
streamWriter.Close();
}
responses.Add(tsk.WebRequest.GetResponseAsync());
}
catch (Exception ex)
{
Logger.mes("Failed to get event data.");
}
}
foreach (var response in responses)
{
try
{
await response.ConfigureAwait(false);
}
catch (Exception ex)
{
Logger.mes("Failed to get event data.");
continue;
}
parseData.Add(ParseData(response));
}
A couple points:
First, it's important to note that you should almost never call .Wait (or .Result) on an async task - you should use await instead. One of the very few exceptions is in the Main method of a console app. The reason is that if you don't block the main thread, your program will simply exit prematurely.
Second, if you need to make multiple HTTP requests that do not depend on each other (i.e. request B does not need the results of request A), then there are huge performance gains to be had by executing them in parallel. Better still, you are not consuming a thread per request because the calls are asynchronous, i.e. they don't block a thread while waiting for a response, so the same thread can effectively fire off many concurrent requests.
I won't re-write your code, but I will suggest how I'd restructure it:
static void Main(string[] args)
{
// start all async tasks in parallel.
var tasks = GetEvents().Select(GetEventDetailsAsync);
// wait for them all to complete. normally you should use await instead of Wait,
// but you can't because you're in the main method of a console app.
Task.WhenAll(task).Wait();
}
static IEnumerable<Event> GetEvents()
{
// build a list of whatever metadata is needed to do your async work.
// do NOT do any actual async work here.
}
async static Task<EventDetailed> GetEventDetailsAsync(Event e)
{
// do all async work here, use await as needed,
// but only for one event (no loops).
}

HttpClient.PostAsync Hanging Until All System.Timers Are Started

I'm having an odd problem with HttpClient and Timers. I have a large number of objects (up to 10,000) that post to a web service. These objects are on timers and post to the service at some n time after creation. The problem is that the Post stalls, until all of the timers have started. See the code below for an example.
Q: Why does the Post hang until all Timers have started? How can it be fixed so that the post functions correctly while the other Timers start?
public class MyObject
{
public void Run()
{
var result = Post(someData).Result;
DoOtherStuff();
}
}
static async Task<string> Post(string data)
{
using (var client = new HttpClient())
{
//Hangs here until all timers are started
var response = await client.PostAsync(new Uri(url), data).ConfigureAwait(continueOnCapturedContext: false);
var text = await response.Content.ReadAsStringAsync().ConfigureAwait(continueOnCapturedContext: false);
return text;
}
}
static void Main(string[] args)
{
for (int i = 0; i < 1000; i++)
{
TimeSpan delay = TimeSpan.FromSeconds(1);
if (i % 2 == 0) delay = TimeSpan.FromDays(1);
System.Timers.Timer timer = new System.Timers.Timer();
timer.AutoReset = false;
timer.Interval = delay.TotalMilliseconds;
timer.Elapsed += (x, y) =>
{
MyObject o = new MyObject();
o.Run();
};
timer.Start();
}
Console.ReadKey();
}
Because you're using up all the ThreadPool threads.
There's a lot wrong with your sample code. You're killing any chance of having reasonable performance, not to mention that the whole thing is inherently unstable.
You're creating a thousand timers in a loop. You're not keeping a reference to any of them, so they will be collected the next time the GC runs - so I'd expect that in practice, very few of them will actually run, unless there's very little memory allocated until they actually get to run.
The timer's Elapsed event will be invoked on a ThreadPool thread. In that thread, you synchronously wait for a bunch of asynchronous calls to complete. That means you're now wasting a thread pool thread, and completely wasting the underlying asynchronicity of the asynchronous method.
The continuation to the asynchronous I/O will be posted to ThreadPool as well - however, the ThreadPool is full of timer callbacks. It will slowly start creating more and more threads to accomodate the amount of work scheduled, until it finally is able to execute the first callback from the asynchronous I/O and it slowly untangles itself. At this point, you likely have more than 1000 threads, and are showing a complete misunderstanding of how to do asynchronous programming.
One way (still rather bad) to fix both problems is to simply make use of asynchronicity all the time:
public class MyObject
{
public async Task Run()
{
var result = await Post(someData);
DoOtherStuff();
}
}
static async Task<string> Post(string data)
{
using (var client = new HttpClient())
{
//Hangs here until all timers are started
var response = await client.PostAsync(new Uri(url), new StringContent(data)).ConfigureAwait(continueOnCapturedContext: false);
var text = await response.Content.ReadAsStringAsync().ConfigureAwait(continueOnCapturedContext: false);
return text;
}
}
static void Main(string[] args)
{
var tasks = new List<Task>();
for (int i = 0; i < 1000; i++)
{
TimeSpan delay = TimeSpan.FromSeconds(1);
if (i % 2 == 0) delay = TimeSpan.FromDays(1);
tasks.Add(Task.Delay(delay).ContinueWith((_) => new MyObject().Run()));
}
Task.WaitAll(tasks.ToArray());
Console.WriteLine("Work done");
Console.ReadKey();
}
A much better way would be to implement some scheduler that handles dispatching the asynchronous I/O with the throttling you need. You probably want to limit the number of concurrent requests or something like that, rather than running the requests in pre-defined intervals (and ignoring the fact that some requests might take very long, timeout or some such).
As mentioned in another reply, that Result property is the problem. when you are using it, asyc will be come sync. If you want to run async operations in console or windows service applications, try Nito AsyncEx library. It creates an AsyncContext. Now you can change void Run to Task Run which is await-able and doesn't need the blocking Result property and in this case await Post will work in the Run method.
static void Main(string[] args)
{
AsyncContext.Run(async () =>
{
var data = await ...;
});
}
As you're running on a console application, which uses the default ThreadPoolSynchronizationContext, you shouldn't really be experiencing the "hanging" feeling as if you are in a UI application. I assume its because Post is taking longer to return than to allocate 1000 timers.
In order for your method to run async, it has to go "async all the way. Using the Task.Result property, as mentioned before will simply block the asynchronous operation until it completes.
Lets see what we need to do for this to be "async all the way":
First, lets change Run from void to async Task so we can await on the Post method:
public async Task Run()
{
var result = await Post(someData);
DoOtherStuff();
}
Now, since Run became awaitable, as it returns a Task, we can turn Timer.Elapsed to an async event handler and await on Run.
static void Main(string[] args)
{
for (int i = 0; i < 1000; i++)
{
TimeSpan delay = TimeSpan.FromSeconds(1);
if (i % 2 == 0) delay = TimeSpan.FromDays(1);
System.Timers.Timer timer = new System.Timers.Timer();
timer.AutoReset = false;
timer.Interval = delay.TotalMilliseconds;
timer.Elapsed += async (x, y) =>
{
MyObject o = new MyObject();
await o.Run();
};
timer.Start();
}
Console.ReadKey();
}
That's it, now we flow async all the way down to the HTTP request and back.
It's because the timers are set up very quickly so they have all finished setting up by the time PostAsync completes. Try putting a Thread.Sleep(1000) after timer.Start, this will slow down the set up of your timers and you should see some PostAsync executions complete.
By the way, Task.Result is a blocking operation, which can cause a deadlock when run from a GUI application. There is more information in this article.

Async network operations never finish

I have several asynchronous network operations that return a task that may never finish:
UdpClient.ReceiveAsync doesn't accept a CancellationToken
TcpClient.GetStream returns a NetworkStream that doesn't respect the CancellationToken on Stream.ReadAsync (checking for cancellation only at the start of the operation)
Both wait for a message that may never come (because of packet loss or no response for example). That means I have phantom tasks that never complete, continuations that will never run and used sockets on hold. I know i can use TimeoutAfter, but that will only fix the continuation problem.
So what am I supposed to do?
So i've made an extension method on IDisposable that creates a CancellationToken that disposes the connection on timeout, so the task finishes and everything carries on:
public static IDisposable CreateTimeoutScope(this IDisposable disposable, TimeSpan timeSpan)
{
var cancellationTokenSource = new CancellationTokenSource(timeSpan);
var cancellationTokenRegistration = cancellationTokenSource.Token.Register(disposable.Dispose);
return new DisposableScope(
() =>
{
cancellationTokenRegistration.Dispose();
cancellationTokenSource.Dispose();
disposable.Dispose();
});
}
And the usage is extremely simple:
try
{
var client = new UdpClient();
using (client.CreateTimeoutScope(TimeSpan.FromSeconds(2)))
{
var result = await client.ReceiveAsync();
// Handle result
}
}
catch (ObjectDisposedException)
{
return null;
}
Extra Info:
public sealed class DisposableScope : IDisposable
{
private readonly Action _closeScopeAction;
public DisposableScope(Action closeScopeAction)
{
_closeScopeAction = closeScopeAction;
}
public void Dispose()
{
_closeScopeAction();
}
}
So what am I supposed to do?
In this particular case, I would rather use UdpClient.Client.ReceiveTimeout and TcpClient.ReceiveTimeout to time out a UDP or TCP receive operation gracefully. I'd like to have the time-out error coming from the socket, rather than from any external source.
If in addition to that I need to observe some other cancellation event, like a UI button click, I would just use WithCancellation from Stephen Toub's "How do I cancel non-cancelable async operations?", like this:
using (var client = new UdpClient())
{
UdpClient.Client.ReceiveTimeout = 2000;
var result = await client.ReceiveAsync().WithCancellation(userToken);
// ...
}
To address the comment, in case ReceiveTimeout has no effect on ReceiveAsync, I'd still use WithCancellation:
using (var client = new UdpClient())
using (var cts = CancellationTokenSource.CreateLinkedTokenSource(userToken))
{
UdpClient.Client.ReceiveTimeout = 2000;
cts.CancelAfter(2000);
var result = await client.ReceiveAsync().WithCancellation(cts.Token);
// ...
}
IMO, this more clearly shows my intentions as a developer and is more readable to a 3rd party. Also, I don't need to catch ObjectDisposedException exeception. I still need to observe OperationCanceledException somewhere in my client code which calls this, but I'd be doing that anyway. OperationCanceledException usually stands out from other exceptions, and I have an option to check OperationCanceledException.CancellationToken to observe the reason for cancellation.
Other than that, there's not much difference from #I3arnon's answer. I just don't feel like I need another pattern for this, as I already have WithCancellation at my disposal.
To further address the comments:
I'd only be catching OperationCanceledException in the client code, i.e.:
async void Button_Click(sender o, EventArgs args)
{
try
{
await DoSocketStuffAsync(_userCancellationToken.Token);
}
catch (Exception ex)
{
while (ex is AggregateException)
ex = ex.InnerException;
if (ex is OperationCanceledException)
return; // ignore if cancelled
// report otherwise
MessageBox.Show(ex.Message);
}
}
Yes, I'll be using WithCancellation with each ReadAsync call and I like that fact, for the following reasons. Firstly, I can create an extension ReceiveAsyncWithToken:
public static class UdpClientExt
{
public static Task<UdpReceiveResult> ReceiveAsyncWithToken(
this UdpClient client, CancellationToken token)
{
return client.ReceiveAsync().WithCancellation(token);
}
}
Secondly, in 3yrs from now I may be reviewing this code for .NET 6.0. By then, Microsoft may have a new API, UdpClient.ReceiveAsyncWithTimeout. In my case, I'll simply replace ReceiveAsyncWithToken(token) or ReceiveAsync().WithCancellation(token) with ReceiveAsyncWithTimeout(timeout, userToken). It would not be so obvious to deal with CreateTimeoutScope.

Categories

Resources