Measuring execution time of async code snippets - c#

I am having trouble with my function for measuring execution time of async code snippets, so I created a console app for easier testing. I was trying to see if the time required for downloading a 200MB file corresponds to the output of the program. However, the app stops executing right after the first command of the code snippet finishes with the output "22 ms". Any ideas why this is happening?
In my real app with a GUI, which is inherently multi-threaded, the measured times were also unrealistic. I tried inserting "Task.Delay" calls into the snippets and it seemed to have no impact on the measured values.
For the sake of brevity, I shortened the code from the real app. Any ideas why this is not working? Alternative ideas on how to measure the time execution of async code snippets?
class Program
{
static void Main(string[] args)
{
MainAsync().GetAwaiter().GetResult();
}
private static async Task MainAsync()
{
var httpClient = new HttpClient();
await MeasureExecutionTimeAsync(
async () => {
// download a 200MB file
var response = await httpClient.GetAsync("http://web4host.net/200MB.zip");
// this never gets executed
var array = await response.Content.ReadAsByteArrayAsync();
File.WriteAllBytes("C:/mytmp/bytefile.xxx", array);
}
);
}
private static async Task MeasureExecutionTimeAsync(Action measuredAction)
{
var stopwatch = new Stopwatch();
stopwatch.Start();
await Task.Run(measuredAction);
stopwatch.Stop();
Console.WriteLine(stopwatch.ElapsedMilliseconds + " ms");
}
}

The problem seems to be with the line
await Task.Run(measuredAction);
Try this instead
private static async Task MainAsync()
{
var httpClient = new HttpClient();
Func<Task> action = async () =>
{
var response = await httpClient.GetAsync("http://web4host.net/200MB.zip").ConfigureAwait(false);
// this never gets executed
var array = await response.Content.ReadAsByteArrayAsync();
File.WriteAllBytes("C:/mytmp/bytefile.xxx", array);
return;
};
await MeasureExecutionTimeAsync(action);
}
private static async Task MeasureExecutionTimeAsync(Func<Task> measuredAction)
{
var stopwatch = new Stopwatch();
stopwatch.Start();
await measuredAction.Invoke();
stopwatch.Stop();
Console.WriteLine(stopwatch.ElapsedMilliseconds + " ms");
}

Related

Make methods run asynchronously

Can someone please look at this code and tell me what I am doing wrong. It seems to me that this 3 methods should run in the same same, but they run each after another. Please take look at time writen on console. In my opinion all Console.WriteLine should show ~60ms.
Code sample below:
private async void GetOneCombination(string firstMarket, string secondMarket, string thirdMarket, decimal amountOfFirstCurrency)
{
Stopwatch sw = new Stopwatch();
sw.Start();
Task<GetMarketResponse> result = _accessMethods.GetOrderbook(firstMarket);
Console.WriteLine(sw.ElapsedMilliseconds); // ~60ms
Task<GetMarketResponse> result1 = _accessMethods.GetOrderbook(secondMarket);
Console.WriteLine(sw.ElapsedMilliseconds); // ~130 ms
Task<GetMarketResponse> result2 = _accessMethods.GetOrderbook(thirdMarket);
Console.WriteLine(sw.ElapsedMilliseconds); // ~200 ms
var getMarketResponses = await Task.WhenAll(result, result1, result2);
}
Edit:
To be hosnest I thought that it don`t matter whats inside this methods, i thought that no matter what is done inside it will be done 3 times at the same time
public async Task<GetMarketResponse> GetOrderbook(string market = "USD")
{
var address = AddressBook._orderbook + market;
var response = MethodExecutionTimeMeasurer.Invoke(() =>
_client.ExecuteGetAsyncPublic<GetMarketResponse>(address), out timespan);
_logger.LogInformation(string.Format("OrderBook requested for [{0}], response message: {1}. Time[ms]:{2}",
address,
response.Status,
timespan));
return response;
}
and ExecuteGetAsyncPublic:
public async Task<T> ExecuteGetAsyncPublic<T>(string method)
where T : IBasicResponse
{
var response = await _httpClient.GetAsync(method).ConfigureAwait(false);
response.EnsureSuccessStatusCode();
var json = await response.Content.ReadAsStringAsync();
var responseData = JsonConvert.DeserializeObject<T>(json);
return responseData;
}
MethodExecutionTimeMeasurer
public static class MethodExecutionTimeMeasurer
{
public static T Invoke<T>(Func<Task<T>> action, out TimeSpan timeSpan)
{
var timer = Stopwatch.StartNew();
var res = action.Invoke();
res.Wait();
timer.Stop();
timeSpan = timer.Elapsed;
return res.Result;
}
public static void Invoke(Action action, out TimeSpan timeSpan)
{
var timer = Stopwatch.StartNew();
action.Invoke();
timer.Stop();
timeSpan = timer.Elapsed;
}
}
There are two problems here:
The GetOrderbook method has an asynchronous signature, but its implementation is synchronous. You are probably getting a warning for the async method lacking an await operator.
The MethodExecutionTimeMeasurer.Invoke has a parameter Func<Task<T>> action (an asynchronous delegate), but the created Task is waited synchronously with the Wait method. So during the task's execution, the current thread is blocked.
Each of the three _accessMethods.GetOrderbook invocations returns a completed task, then the combined task Task.WhenAll(result, result1, result2) is also completed upon creation, and in short from the current thread's perspective nothing is running asynchronously. This case is very similar with a question that was asked yesterday, check it out.
Calling an async Task method does not immediately start on a new thread. It will run on the thread that it was called on until it encounters an await.
so for example
var task = DoSomething();
public async Task DoSomething()
{
// MAIN THREAD
await Task.Delay(1);
// WORKER THREAD
}
If you do it like this it will probably work
public async Task<GetMarketResponse> GetOrderbook(string market = "USD")
{
await Task.Delay(1);
var address = AddressBook._orderbook + market;
var response = MethodExecutionTimeMeasurer.Invoke(() =>
_client.ExecuteGetAsyncPublic<GetMarketResponse>(address), out timespan);
_logger.LogInformation(string.Format("OrderBook requested for [{0}], response message: {1}. Time[ms]:{2}",
address,
response.Status,
timespan));
return response;
}
Another approach you can take is
Parallel.Invoke(
() => _accessMethods.GetOrderbook(firstMarket).Wait(),
() => _accessMethods.GetOrderbook(secondMarket).Wait(),
() => _accessMethods.GetOrderbook(thirdMarket).Wait(),
);

Logging operations, how to implement better

I need to implement logging of some calls of methods with many logging information (time etc). I can do it like this:
var stopwatch = new Stopwatch();
OCRResult ocrResult = await ocr.GetTextAsync(dataStream, filename, language);
stopwatch.Stop();
// log here, with time, result etc
It would work, but I don't like this approach. First at all, I have many such calls in many places and I have to dublicate code. Secondly, this approach violates SRP (single responsible principle), where each call does one work. I need to do a wrapper or use Strategy pattern, in any case I should create one more class to do it. But how to implement it?
You can create a generic method that measures the time of a function and logs it:
public static void LogFunc<T>(Func<T> func)
{
var stopwatch = Stopwatch.StartNew();
T result = func();
stopwatch.Stop();
long time = stopwatch.ElapsedMilliseconds;
// log here, with time, result etc
}
LogFunc(async () => await ocr.GetTextAsync(dataStream, filename, language));
An async version of this method:
public static async Task LogFuncAsync<T>(Func<Task<T>> func)
{
var stopwatch = Stopwatch.StartNew();
T result = await func();
stopwatch.Stop();
long time = stopwatch.ElapsedMilliseconds;
// log here, with time, result etc
}
await LogFuncAsync(() => ocr.GetTextAsync(dataStream, filename, language));
Follow "Kfir Guy" answer's I modified his answer and got the following:
public static async Task LogFuncAsync<T>(Func<Task<T>> func)
{
var stopwatch = Stopwatch.StartNew();
T result = await func();
stopwatch.Stop();
long time = stopwatch.ElapsedMilliseconds;
// log here, with time, result etc
}
and call it:
await Utils.LogFuncAsync(async () => ocrResult = await ocr.GetTextAsync(dataStream, filename, language));

Loop with Asyn and await [duplicate]

I've been trying for a while to get something I thought would be simple working with .NET 4.5
I want to fire off two long running tasks at same time and collect the
results in in the best C# 4.5 (RTM) way
The following works but I don't like it because:
I want Sleep to be an async method so it can await other methods
It just looks clumsy with Task.Run()
I don't think this is even using any new language features at all!
Working code:
public static void Go()
{
Console.WriteLine("Starting");
var task1 = Task.Run(() => Sleep(5000));
var task2 = Task.Run(() => Sleep(3000));
int totalSlept = task1.Result + task2.Result;
Console.WriteLine("Slept for a total of " + totalSlept + " ms");
}
private static int Sleep(int ms)
{
Console.WriteLine("Sleeping for " + ms);
Thread.Sleep(ms);
Console.WriteLine("Sleeping for " + ms + " FINISHED");
return ms;
}
Non working code:
Update: This actually works and is the correct way to do it, the only problem is the Thread.Sleep
This code doesn't work because the call to Sleep(5000) immediately starts the task running so Sleep(1000) doesn't run until it has completed. This is true even though Sleep is async and I'm not using await or calling .Result too soon.
I thought maybe there is a way to get a non-running Task<T> by calling an async method so I could then call Start() on the two tasks, but I can't figure out how to get a Task<T> from calling an async method.
public static void Go()
{
Console.WriteLine("Starting");
var task1 = Sleep(5000); // blocks
var task2 = Sleep(1000);
int totalSlept = task1.Result + task2.Result;
Console.WriteLine("Slept for " + totalSlept + " ms");
}
private static async Task<int> Sleep(int ms)
{
Console.WriteLine("Sleeping for " + ms);
Thread.Sleep(ms);
return ms;
}
async Task<int> LongTask1() {
...
return 0;
}
async Task<int> LongTask2() {
...
return 1;
}
...
{
Task<int> t1 = LongTask1();
Task<int> t2 = LongTask2();
await Task.WhenAll(t1,t2);
//now we have t1.Result and t2.Result
}
You should use Task.Delay instead of Sleep for async programming and then use Task.WhenAll to combine the task results. The tasks would run in parallel.
public class Program
{
static void Main(string[] args)
{
Go();
}
public static void Go()
{
GoAsync();
Console.ReadLine();
}
public static async void GoAsync()
{
Console.WriteLine("Starting");
var task1 = Sleep(5000);
var task2 = Sleep(3000);
int[] result = await Task.WhenAll(task1, task2);
Console.WriteLine("Slept for a total of " + result.Sum() + " ms");
}
private async static Task<int> Sleep(int ms)
{
Console.WriteLine("Sleeping for {0} at {1}", ms, Environment.TickCount);
await Task.Delay(ms);
Console.WriteLine("Sleeping for {0} finished at {1}", ms, Environment.TickCount);
return ms;
}
}
While your Sleep method is async, Thread.Sleep is not. The whole idea of async is to reuse a single thread, not to start multiple threads. Because you've blocked using a synchronous call to Thread.Sleep, it's not going to work.
I'm assuming that Thread.Sleep is a simplification of what you actually want to do. Can your actual implementation be coded as async methods?
If you do need to run multiple synchronous blocking calls, look elsewhere I think!
To answer this point:
I want Sleep to be an async method so it can await other methods
you can maybe rewrite the Sleep function like this:
private static async Task<int> Sleep(int ms)
{
Console.WriteLine("Sleeping for " + ms);
var task = Task.Run(() => Thread.Sleep(ms));
await task;
Console.WriteLine("Sleeping for " + ms + "END");
return ms;
}
static void Main(string[] args)
{
Console.WriteLine("Starting");
var task1 = Sleep(2000);
var task2 = Sleep(1000);
int totalSlept = task1.Result +task2.Result;
Console.WriteLine("Slept for " + totalSlept + " ms");
Console.ReadKey();
}
running this code will output :
Starting
Sleeping for 2000
Sleeping for 1000
*(one second later)*
Sleeping for 1000END
*(one second later)*
Sleeping for 2000END
Slept for 3000 ms
It's weekend now!
public async void Go()
{
Console.WriteLine("Start fosterage...");
var t1 = Sleep(5000, "Kevin");
var t2 = Sleep(3000, "Jerry");
var result = await Task.WhenAll(t1, t2);
Console.WriteLine($"My precious spare time last for only {result.Max()}ms");
Console.WriteLine("Press any key and take same beer...");
Console.ReadKey();
}
private static async Task<int> Sleep(int ms, string name)
{
Console.WriteLine($"{name} going to sleep for {ms}ms :)");
await Task.Delay(ms);
Console.WriteLine("${name} waked up after {ms}ms :(";
return ms;
}
This article helped explain a lot of things. It's in FAQ style.
Async/Await FAQ
This part explains why Thread.Sleep runs on the same original thread - leading to my initial confusion.
Does the “async” keyword cause the invocation of a method to queue to
the ThreadPool? To create a new thread? To launch a rocket ship to
Mars?
No. No. And no. See the previous questions. The “async” keyword
indicates to the compiler that “await” may be used inside of the
method, such that the method may suspend at an await point and have
its execution resumed asynchronously when the awaited instance
completes. This is why the compiler issues a warning if there are no
“awaits” inside of a method marked as “async”.

Use DownloadFileTaskAsync to download all files at once

Given a input text file containing the Urls, I would like to download the corresponding files all at once. I use the answer to this question
UserState using WebClient and TaskAsync download from Async CTP as reference.
public void Run()
{
List<string> urls = File.ReadAllLines(#"c:/temp/Input/input.txt").ToList();
int index = 0;
Task[] tasks = new Task[urls.Count()];
foreach (string url in urls)
{
WebClient wc = new WebClient();
string path = string.Format("{0}image-{1}.jpg", #"c:/temp/Output/", index+1);
Task downloadTask = wc.DownloadFileTaskAsync(new Uri(url), path);
Task outputTask = downloadTask.ContinueWith(t => Output(path));
tasks[index] = outputTask;
}
Console.WriteLine("Start now");
Task.WhenAll(tasks);
Console.WriteLine("Done");
}
public void Output(string path)
{
Console.WriteLine(path);
}
I expected that the downloading of the files would begin at the point of "Task.WhenAll(tasks)". But it turns out that the output look likes
c:/temp/Output/image-2.jpg
c:/temp/Output/image-1.jpg
c:/temp/Output/image-4.jpg
c:/temp/Output/image-6.jpg
c:/temp/Output/image-3.jpg
[many lines deleted]
Start now
c:/temp/Output/image-18.jpg
c:/temp/Output/image-19.jpg
c:/temp/Output/image-20.jpg
c:/temp/Output/image-21.jpg
c:/temp/Output/image-23.jpg
[many lines deleted]
Done
Why does the downloading begin before WaitAll is called? What can I change to achieve what I would like (i.e. all tasks will begin at the same time)?
Thanks
Why does the downloading begin before WaitAll is called?
First of all, you're not calling Task.WaitAll, which synchronously blocks, you're calling Task.WhenAll, which returns an awaitable which should be awaited.
Now, as others said, when you call an async method, even without using await on it, it fires the asynchronous operation, because any method conforming to the TAP will return a "hot task".
What can I change to achieve what I would like (i.e. all tasks will
begin at the same time)?
Now, if you want to defer execution until Task.WhenAll, you can use Enumerable.Select to project each element to a Task, and materialize it when you pass it to Task.WhenAll:
public async Task RunAsync()
{
IEnumerable<string> urls = File.ReadAllLines(#"c:/temp/Input/input.txt");
var urlTasks = urls.Select((url, index) =>
{
WebClient wc = new WebClient();
string path = string.Format("{0}image-{1}.jpg", #"c:/temp/Output/", index);
var downloadTask = wc.DownloadFileTaskAsync(new Uri(url), path);
Output(path);
return downloadTask;
});
Console.WriteLine("Start now");
await Task.WhenAll(urlTasks);
Console.WriteLine("Done");
}
Why does the downloading begin before WaitAll is called?
Because:
Tasks created by its public constructors are referred to as “cold”
tasks, in that they begin their life cycle in the non-scheduled
TaskStatus.Created state, and it’s not until Start is called on these
instances that they progress to being scheduled. All other tasks begin
their life cycle in a “hot” state, meaning that the asynchronous
operations they represent have already been initiated and their
TaskStatus is an enumeration value other than Created. All tasks
returned from TAP methods must be “hot.”
Since DownloadFileTaskAsync is a TAP method, it returns "hot" (that is, already started) task.
What can I change to achieve what I would like (i.e. all tasks will begin at the same time)?
I'd look at TPL Data Flow. Something like this (I've used HttpClient instead of WebClient, but, actually, it doesn't matter):
static async Task DownloadData(IEnumerable<string> urls)
{
// we want to execute this in parallel
var executionOptions = new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = Environment.ProcessorCount };
// this block will receive URL and download content, pointed by URL
var donwloadBlock = new TransformBlock<string, Tuple<string, string>>(async url =>
{
using (var client = new HttpClient())
{
var content = await client.GetStringAsync(url);
return Tuple.Create(url, content);
}
}, executionOptions);
// this block will print number of bytes downloaded
var outputBlock = new ActionBlock<Tuple<string, string>>(tuple =>
{
Console.WriteLine($"Downloaded {(string.IsNullOrEmpty(tuple.Item2) ? 0 : tuple.Item2.Length)} bytes from {tuple.Item1}");
}, executionOptions);
// here we tell to donwloadBlock, that it is linked with outputBlock;
// this means, that when some item from donwloadBlock is being processed,
// it must be posted to outputBlock
using (donwloadBlock.LinkTo(outputBlock))
{
// fill downloadBlock with input data
foreach (var url in urls)
{
await donwloadBlock.SendAsync(url);
}
// tell donwloadBlock, that it is complete; thus, it should start processing its items
donwloadBlock.Complete();
// wait while downloading data
await donwloadBlock.Completion;
// tell outputBlock, that it is completed
outputBlock.Complete();
// wait while printing output
await outputBlock.Completion;
}
}
static void Main(string[] args)
{
var urls = new[]
{
"http://www.microsoft.com",
"http://www.google.com",
"http://stackoverflow.com",
"http://www.amazon.com",
"http://www.asp.net"
};
Console.WriteLine("Start now.");
DownloadData(urls).Wait();
Console.WriteLine("Done.");
Console.ReadLine();
}
Output:
Start now.
Downloaded 1020 bytes from http://www.microsoft.com
Downloaded 53108 bytes from http://www.google.com
Downloaded 244143 bytes from http://stackoverflow.com
Downloaded 468922 bytes from http://www.amazon.com
Downloaded 27771 bytes from http://www.asp.net
Done.
What can I change to achieve what I would like (i.e. all tasks will
begin at the same time)?
To synchronize the beginning of the download you could use Barrier class.
public void Run()
{
List<string> urls = File.ReadAllLines(#"c:/temp/Input/input.txt").ToList();
Barrier barrier = new Barrier(url.Count, ()=> {Console.WriteLine("Start now");} );
Task[] tasks = new Task[urls.Count()];
Parallel.For(0, urls.Count, (int index)=>
{
string path = string.Format("{0}image-{1}.jpg", #"c:/temp/Output/", index+1);
tasks[index] = DownloadAsync(Uri(urls[index]), path, barrier);
})
Task.WaitAll(tasks); // wait for completion
Console.WriteLine("Done");
}
async Task DownloadAsync(Uri url, string path, Barrier barrier)
{
using (WebClient wc = new WebClient())
{
barrier.SignalAndWait();
await wc.DownloadFileAsync(url, path);
Output(path);
}
}

How to determine the status of the job Async/Await

i read this guide line from here http://blog.stephencleary.com/2012/02/async-and-await.html
here i got few couple of code but not very clear to me.
1)
public async Task DoOperationsInParallelAsync()
{
Task[] tasks = new Task[3];
tasks[0] = DoOperation0();
tasks[1] = DoOperation1();
tasks[2] = DoOperation2();
// At this point, all three tasks are running in parallel.
// Now, we await them all.
await Task.WhenAll(tasks);
}
in the above we are creating multiple task but suppose when all task will run parallel then DoOperation2() may be finish first and DoOperation0() and at last DoOperation1() complete. if i want to show that message like DoOperation2() is completed in console windows then how could i do this. how could i detect that which task complete when multiple is running.
2) when we run any function with the help of async/await the does it run as background thread or foreground thread.
3)
public async Task<int> GetFirstToRespondAsync()
{
// Call two web services; take the first response.
Task<int>[] tasks = new[] { WebService1(), WebService2() };
// Await for the first one to respond.
Task<int> firstTask = await Task.WhenAny(tasks);
// Return the result.
return await firstTask;
}
i do not understand why the person wrote Await for the first one to respond.
// Await for the first one to respond.
Task firstTask = await Task.WhenAny(tasks);
why first one...why not second one because two task are running here.
please guide me and drive out my confusion. thanks
Because it's a console app, you need to wait for the task to finish. Here's an example of how to return a string from a task:
class WhenAny
{
public static async Task<string> GetFirstToRespondAsync()
{
// Call two web services; take the first response.
Task<string>[] tasks = new[] { Task1(), Task2() };
// Await for the first one to respond.
Task<string> firstTask = await Task.WhenAny(tasks);
// Return the result.
return firstTask.Result;
}
private static async Task<string> Task1()
{
await Task.Delay(3000);
return "Task1";
}
private static async Task<string> Task2()
{
await Task.Delay(1000);
return "Task2";
}
}
Call that from the Main function as follows:
static void Main(string[] args)
{
var t = WhenAny.GetFirstToRespondAsync();
t.ContinueWith((taskName) =>
{
string result = taskName.Result;
Console.WriteLine("Result: " + result);
});
t.Wait();
Console.ReadLine();
}
That should return the task that completes first, and you can access that information from the Task.Result
Awaiting a method does not, in itself, create an additional thread. What it does is create a callback to avoid blocking the current thread (typically this is used to not block the UI thread).
WhenAny returns when the earliest completed operation returns. That doesn't mean the first in the list that you provide. So, the code above will always show 1000, even though it's the second task.
For completeness, here's the same thing with WhenAll:
class WhenAll
{
public static async Task<string[]> WaitForAllAsync()
{
// Call two web services; take the first response.
Task<string>[] tasks = new[] { Task1(), Task2(), Task3() };
// Wait for a tasks
string[] results = await Task.WhenAll(tasks);
// Return the result.
return results;
}
private static async Task<string> Task1()
{
await Task.Delay(3000);
return "Task1";
}
private static async Task<string> Task2()
{
await Task.Delay(1000);
return "Task2";
}
private static async Task<string> Task3()
{
await Task.Delay(5000);
return "Task3";
}
}
And to call it:
static void Main(string[] args)
{
var t = WhenAll.WaitForAllAsync();
t.ContinueWith((task) =>
{
string[] result = task.Result;
foreach(string taskname in result)
{
Console.WriteLine("Result: " + taskname);
}
});
t.Wait();
Console.ReadLine();
}
You can use ContinueWith method for every task that will update the progress.
So...
foreach (var t in tasks)
{
t.ContinueWith(Console.WriteLine("Hey I am done"));
}
1) Pass in a callback function
public async Task DoOperationsInParallelAsync(Action<Task<int>> completed)
{
var uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();
var tasks = new[] { DoOperation0(), DoOperation1(), DoOperation2() };
var completedTasks = tasks.Select(x => x.ContinueWith(completed, uiScheduler)).ToArray();
await Task.WhenAll(completedTasks);
}
private async void Button1_Click(object sender, EventArgs e)
{
await DoOperationsInParallelAsync(t => {
Label1.Text = string.Format("Task finished with {0}", t.Result);
});
}
2) The Task will run on the threadpool unless you specify it as long running or provide a TaskScheduler.
3) When only the first result matters (computation is redundant or time sensitive) such as grabbing stock prices from various providers mirroring similar data.

Categories