My wpf program reads commands from a text file, and then sends those commands out over HttpClient.
Each GetAsync response takes about 2 seconds to complete. This seems excessively long, especially when I have 50 commands to send.
Is this a normal amount of time for HttpClient to send/receive a GetAsync Message? Is there a faster way to do this?
static readonly HttpClient client = new HttpClient();
public MainWindow()
{
InitializeComponent();
}
private async void Register_ClickAsync(object sender, RoutedEventArgs e)
{
int counter = 0;
string line;
System.IO.StreamReader file = new System.IO.StreamReader(#"C\path.txt");
while ((line = file.ReadLine()) != null)
{
try
{
var watch = Stopwatch.StartNew();
HttpResponseMessage response = await client.GetAsync(line);
response.EnsureSuccessStatusCode();
string responseBody = await response.Content.ReadAsStringAsync();
watch.Stop();
var elapsedMS = watch.ElapsedMilliseconds;
RequestTextBox.Text += "\n" + elapsedMS;
}
catch (HttpRequestException ex)
{
Console.WriteLine("\nException Caught!");
Console.WriteLine("Message :{0} ", ex.Message);
this.RequestTextBox.Text += ("\n" + "Message: {0} ", ex.Message);
}
}
file.Close();
}
}
UPDATE:
This original program is a .net Core WPF app. I created a .net framework WPF app with the exact same code. The .net framework app takes 2000 ms to send the first HttpClient GetAsync command, and then <10 ms for subsequent commands. This is a massive performance increase. Does anyone have an explanation? I have been unable to find any articles explaining this.
Your code is awaiting for each request.
You can create many tasks by calling GetAsync and then wait them all with Task.WhenAll(). It will be more faster.
You are not using the async paradigm correctly. You are awaiting an async call immediately, and as a result it acts the same as a synchronous method. The idea of an async method is that it starts work and runs in the background, while not blocking other threads from executing. This allows you to run many threads at once and then return them when you are ready to use them. I would highly recommend the msft docs in this case. They use the example of making breakfast, in this example they are doing it incorrectly, as you are in your question:
Coffee cup = PourCoffee();
Console.WriteLine("coffee is ready");
Task<Egg> eggsTask = FryEggs(2);
Egg eggs = await eggsTask;
Console.WriteLine("eggs are ready");
Task<Bacon> baconTask = FryBacon(3);
Bacon bacon = await baconTask;
Console.WriteLine("bacon is ready");
Task<Toast> toastTask = ToastBread(2);
Toast toast = await toastTask;
ApplyButter(toast);
ApplyJam(toast);
Console.WriteLine("toast is ready");
Juice oj = PourOJ();
Console.WriteLine("oj is ready");
Console.WriteLine("Breakfast is ready!");
To fix it you must call Task.WhenAny() or Task.WhenAll(). This allows you to run all of the tasks at once and return them after they have finished (or as they finish). This will greatly improve your performance.
static async Task Main(string[] args)
{
Coffee cup = PourCoffee();
Console.WriteLine("coffee is ready");
var eggsTask = FryEggsAsync(2);
var baconTask = FryBaconAsync(3);
var toastTask = MakeToastWithButterAndJamAsync(2);
var allTasks = new List<Task>{eggsTask, baconTask, toastTask};
while (allTasks.Any())
{
Task finished = await Task.WhenAny(allTasks);
if (finished == eggsTask)
{
Console.WriteLine("eggs are ready");
}
else if (finished == baconTask)
{
Console.WriteLine("bacon is ready");
}
else if (finished == toastTask)
{
Console.WriteLine("toast is ready");
}
allTasks.Remove(finished);
}
Juice oj = PourOJ();
Console.WriteLine("oj is ready");
Console.WriteLine("Breakfast is ready!");
async Task<Toast> MakeToastWithButterAndJamAsync(int number)
{
var toast = await ToastBreadAsync(number);
ApplyButter(toast);
ApplyJam(toast);
return toast;
}
}
Related
I am trying to upload files to S3, to improve performance I am trying to spawn a threadpool of 100 threads to execute this task however when I trigger my console application it just stops executing once I run it and breaks.
This is what I tried so far,
string bucketName = <<bucket-name>>;
var threadCount = Environment.ProcessorCount;
ThreadPool.SetMaxThreads(100, 100);
ThreadPool.QueueUserWorkItem(new WaitCallback((obj) =>
{
UploadFile(bucketName);
}));
public void UploadFile(string bucketName)
{
TransferUtilityUploadDirectoryRequest uploadDirectoryRequest;
string directoryName= #"D:\Files\100KB";
try
{
uploadDirectoryRequest = new TransferUtilityUploadDirectoryRequest
{
BucketName = bucketName,
Directory = directoryName,
KeyPrefix = "upload_dir",
UploadFilesConcurrently = true
};
var stopwatch = new Stopwatch();
stopwatch.Start();
transferUtility.UploadDirectory(uploadDirectoryRequest);
stopwatch.Stop();
Console.WriteLine("Time Elapsed:"+stopwatch.Elapsed);
}
catch (AmazonS3Exception exception)
{
Console.WriteLine(exception.Message);
}
catch (Exception exception)
{
Console.WriteLine(exception.Message);
}
}
Any idea what I could be doing wrong with respect to using the threadpool? What would be the correct way to write this logic?
I am attempting to use the TPL in a windows service for efficient asynchronous processing. The service runs in an infinite loop, until the service is cancelled.
Here is the code that I'm using for the main service methods:
private CancellationTokenSource cancellationTokenSource;
private readonly List<Task> tasks = new List<Task>();
protected override void OnStart(string[] args)
{
cancellationTokenSource = new CancellationTokenSource();
tasks.Add(Task.Factory.StartNew(() =>
{
Worker(cancellationTokenSource.Token);
}, cancellationTokenSource.Token));
}
private async void Worker(CancellationToken token)
{
bool keepGoing = true;
while (keepGoing)
{
try
{
if (token.IsCancellationRequested)
{
token.ThrowIfCancellationRequested();
}
//Parallel.ForEach(processors, processor =>
//{
await processor.Process();
//});
}
catch (Exception ex)
{
if (ex is OperationCanceledException)
{
keepGoing = false;
}
else
{
//write log here
}
}
finally
{
await Task.Delay(configurationSettings.OperationSettings.ServiceOperationDelay, token).ContinueWith(tsk => { });
}
}
}
protected override void OnStop()
{
cancellationTokenSource.Cancel();
using var mres = new ManualResetEventSlim();
using (cancellationTokenSource.Token.Register(() => mres.Set()))
{
Task.Factory.ContinueWhenAll(tasks.ToArray(), (t) => mres.Set());
mres.Wait();
}
}
The call to the processor basically does the following:
var records = await interfaceService.Get()
foreach record retrieved
await interfaceService.Patch()
The service utilizes an HttpClient instance to make requests.
**Get:**
using HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get,
"");
using HttpResponseMessage response = await httpClient.SendAsync(request);
if (response.IsSuccessStatusCode)
{
//return results
}
else
{
throw Exception("Foo bar")
}
**Patch**
using HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Patch, "")
{
Content = new StringContent(JsonConvert.SerializeObject(body), Encoding.UTF8, "application/json")
};
using HttpResponseMessage response = await httpClient.SendAsync(request);
The issue that I am encountering is that if the endpoint becomes unavailable, the service just doesn't effectively catch any exception or responses returned and for a lack of better terminology, falls in a hole. I believe my issue is with the way that the tasks are being managed.
What I want to ultimately be able to do is have the service with each iteration of the loop
Fire off specific tasks asynchronously, which perform the get/patch operation, at once
Wait until all are completed.
Log results of each to a file
Go to sleep
Start at step #1
In addition, when the service stops, I want to gracefully stop processing of each task.
Any help with this is greatly appreciated!
I've done a lot of work over the past week, working with creating background task for a windows universal project. I've having a hard, and starting believe it is not possible triggering a background task to run when the device screen is locked. I'm using SystemTriggerType.Useraway to trigger the background task. I'll post what i've got so far. Any help with this would be awesome!
Here's how I am registering the background task
public static void RegisterTask()
{
try
{
var taskRegistered = false;
var builder = new BackgroundTaskBuilder();
foreach (var task in BackgroundTaskRegistration.AllTasks)
{
if (task.Value.Name == "ResponderBackgroundTask")
{
Debug.WriteLine(task.Value.Name + " Task Already Registered!!");
taskRegistered = true;
break;
}
}
if (!taskRegistered)
{
builder.Name = "ResponderBackgroundTask";
builder.TaskEntryPoint = "BackgroundGps.BackgroundTask";
builder.AddCondition(new SystemCondition(SystemConditionType.UserNotPresent));
builder.AddCondition(new SystemCondition(SystemConditionType.InternetAvailable));
builder.SetTrigger(new SystemTrigger(SystemTriggerType.UserAway, false));
builder.CancelOnConditionLoss = true;
var register = builder.Register();
register.Completed += new BackgroundTaskCompletedEventHandler(OnComplete);
}
}
catch (Exception ex)
{
Debug.WriteLine(ex.ToString());
throw;
}
}
Here is the backgroundtask:
async public void Run(IBackgroundTaskInstance taskInstance)
{
taskInstance.Canceled += new BackgroundTaskCanceledEventHandler(OnCanceled);
Debug.WriteLine("Inside Run.......");
BackgroundTaskDeferral deferral = taskInstance.GetDeferral();
await Geolocate();
deferral.Complete();
}
async static Task<HttpResponseMessage> Geolocate()
{
Debug.WriteLine("Inside Async Geolocate");
HttpResponseMessage response = new HttpResponseMessage();
Geolocator geolocator = new Geolocator();
geolocator.DesiredAccuracy = (PositionAccuracy) 20;
geolocator.DesiredAccuracyInMeters = 30;
var networkStatus = NetworkInformation.GetInternetConnectionProfile();
bool status = true;
while (status)
{
networkStatus = NetworkInformation.GetInternetConnectionProfile();
Geoposition position = await geolocator.GetGeopositionAsync().AsTask();
var latitude = position.Coordinate.Point.Position.Latitude;
var longitude = position.Coordinate.Point.Position.Longitude;
HttpClient client = new HttpClient();
response = await client.GetAsync("http://www.mylocation.com/location?=latitude&longitude");
Debug.WriteLine(response);
if (networkStatus == null)
{
status = false;
}
if (cancelRequest == true)
{
return response;
}
await Task.Delay(15000);
}
return response;
}
I had some issues with background task in UWP project when I've used it for push notifications.
The main issue with UWP BackgroundTasks is that they suppose to be very light and consume not much of CPU time, otherwise the OS shuts it down.
My problem was, that I've tried to access the local database by using very heavy service, which took CPU time and were shutdown by the OS. My logs were cut in the middle of a line, cause my logger won't be fast enough to write the message.
Try to put some logs in your BackgroundTask inorder to see if he raised by the trigger, and look for a heavy operation that can cause it to be canceled.
Web requests can be also the problem...
The application is for the Windows 8 Mobile platform, and it tends to crash when I send some data to the server at a point during it's life cycle.
await writer.StoreAsync();
An exception of type 'System.Exception' occurred in mscorlib.ni.dll but was not handled in user code
Additional information: An established connection was aborted by the software in your host machine. (Exception from HRESULT: 0x80072745)
Even if I put it in a try catch, I can't throw the exception, since it feels it still closes the program.
When a button is pressed, it sends a message to the server;
private void button_Click(object sender, RoutedEventArgs e)
{
Task t = new Task(TalkToServer);
if (t.IsCompleted != t.IsCompleted)
{
}
else
{
t.RunSynchronously();
}
}
So if I press the button it will start a new task. If the task is completed, then run the task, else if it isn't then do not.
private async void TalkToServer()
{
if (clientSocket == null)
return;
DataWriter writer = new DataWriter(clientSocket.OutputStream);
MessageData md = new MessageData();
md.MyUser = new User("us", "ps");
md.MyType = MessageData.mType.REQUESTMEMBERS;
string output = JsonConvert.SerializeObject(md);
writer.WriteString(output);
await writer.StoreAsync();
await writer.FlushAsync();
writer.DetachStream();
}
This is the method call that sends the data, but await writer.StoreAsync();
tends to crash the program. This code is used in the beggining of a program on a seperate page and it works, but it dues to
EDIT ---- after looking at the further reading that user method man had presented, I changed the implementation to :
private async void button_Click(object sender, RoutedEventArgs e)
{
await sendInfo();
}
private async Task sendInfo()
{
if (clientSocket == null)
return;
DataWriter writer = new DataWriter(clientSocket.OutputStream);
MessageData md = new MessageData();
md.MyUser = new User("us", "ps");
md.MyType = MessageData.mType.REQUESTMEMBERS;
string output = JsonConvert.SerializeObject(md);
writer.WriteString(output);
await writer.StoreAsync();
await writer.FlushAsync();
writer.DetachStream();
return ;
}
Also the title was changed
this program reads a list of web site then saves them.
i found it runs good for the first 2 url requests. then goes very slow (about 5 min per request)
the time spend on row 1 and row 2 are only 2 second.
Then all other will be about 5 min each.
When i debug , i see it actually tooks long in wb.Navigate(url.ToString());
public static async Task<bool> test()
{
long totalCnt = rows.Count();
long procCnt = 0;
foreach (string url in rows)
{
procCnt++;
string webStr = load_WebStr(url).Result;
Console.WriteLine(DateTime.Now+ "["+procCnt + "/" + totalCnt+"] "+url);
}
return true;
}
public static async Task<string> load_WebStr(string url)
{
var tcs = new TaskCompletionSource<string>();
var thread = new Thread(() =>
{
EventHandler idleHandler = null;
idleHandler = async (s, e) =>
{
// handle Application.Idle just once
Application.Idle -= idleHandler;
// return to the message loop
await Task.Yield();
// and continue asynchronously
// propogate the result or exception
try
{
var result = await webBrowser_Async(url);
tcs.SetResult(result);
}
catch (Exception ex)
{
tcs.SetException(ex);
}
// signal to exit the message loop
// Application.Run will exit at this point
Application.ExitThread();
};
// handle Application.Idle just once
// to make sure we're inside the message loop
// and SynchronizationContext has been correctly installed
Application.Idle += idleHandler;
Application.Run();
});
// set STA model for the new thread
thread.SetApartmentState(ApartmentState.STA);
// start the thread and await for the task
thread.Start();
try
{
return await tcs.Task;
}
finally
{
thread.Join();
}
}
public static async Task<string> webBrowser_Async(string url)
{
string result = "";
using (var wb = new WebBrowser())
{
wb.ScriptErrorsSuppressed = true;
TaskCompletionSource<bool> tcs = null;
WebBrowserDocumentCompletedEventHandler documentCompletedHandler = (s, e) =>
tcs.TrySetResult(true);
tcs = new TaskCompletionSource<bool>();
wb.DocumentCompleted += documentCompletedHandler;
try
{
wb.Navigate(url.ToString());
// await for DocumentCompleted
await tcs.Task;
}
catch
{
Console.WriteLine("BUG!");
}
finally
{
wb.DocumentCompleted -= documentCompletedHandler;
}
// the DOM is ready
result = wb.DocumentText;
}
return result;
}
I recognize a slightly modified version of the code I used to answer quite a few WebBrowser-related questions. Was it this one? It's always a good idea to include a link to the original source.
Anyhow, the major problem in how you're using it here is perhaps the fact that you create and destroy an instance of WebBrowser control for every URL from your list.
Instead, you should be re-using a single instance of WebBrowser (or a pool of WebBrowser objects). You can find both versions here.