Make methods run asynchronously - c#

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(),
);

Related

Async method somehow yields control when it shouldn't

Consider the code below
static void Main(string[] args)
{
var ts = new CancellationTokenSource();
CancellationToken ct = ts.Token;
Task<string> task = Task.Run(() =>
{
ct.ThrowIfCancellationRequested();
var task2 = ActualAsyncTask();
while (!task2.IsCompleted)
{
var t = DateTime.Now;
while (DateTime.Now - t < TimeSpan.FromSeconds(1))
{
}
ct.ThrowIfCancellationRequested();
}
return task2;
}, ct);
Console.ReadLine();
ts.Cancel();
Console.ReadLine();
}
static async Task<string> ActualAsyncTask()
{
await Task.Delay(1000);
for(int i = 0; i < 100; ++i)
{
var t = DateTime.Now;
while (DateTime.Now - t < TimeSpan.FromSeconds(1))
{
}
Console.WriteLine("tick");
}
return "success";
}
It spawns a task that busy-waits for a cancellation request while an asynchronous method also busy-waits and prints some text into console.
When you let it run for a few seconds and then press enter, the task will throw the cancellation exception. While it's an interesting trick, I don't understand how the async method is able to yield control and make it possible.
Both the anonymous lambda within the task and the asynchronous method report to run on the same worker thread, which means they should be synchronous. In my understanding this setup should not throw the cancellation exception past the first 1 second await, because past that point there are no more awaits to allow the while loop of the anonymous lambda to gain control of the thread flow, yet somehow they seemingly both run in parallel using one thread.
If I remove the await command entirely, the execution becomes as expected - sending a cancellation request no longer interrupts the task. What am I missing?

.NET CORE Time asynced method

I have several asynec methods.
One of them triggers a POST method which start a process. I then need to 'sample' the results of another GET method every 10 minutes, and check if the status has changed from "pending" to "success" .
I tryed usingSystem.Threading.Timer with no luck, complaining about my method being asynced .
Error CS0407 'Task Campaigns.repeat(object)' has the wrong return type Campaigns
This is my code:
public async Task waitForCampaignLoadAsync(string Uri)
{
...........
var container = JsonConvert.DeserializeObject<CampaignTempleteStatus>(json);
if(container.status == "pending")
{
var autoEvent = new AutoResetEvent(false);
//The next row triggers the error
var stateTimer = new Timer(repeat, autoEvent, 1000, (1000 * 60 * 10));
//How can I keep repeating this, until (bool isFinished = true)??
}
public async Task repeat(Object stateInfo)
{
if(...)
isFinished = true;
}
Another thing is , how do I pass extra info inside repeat function? I need to pass the Uri input for inner ussage ?
When an asynchronous method starts getting complicated it's a sure sign something is wrong. Most of the time async code looks almost the same as synchronous code with the addition of await.
A simple polling loop could be as simple as :
public async Task<string> waitForCampaignLoadAsync(string uri)
{
var client=new HttpClient();
for(int i=0;i<30;i++)
{
token.ThrowIfCancellationRequested();
var json = await client.GetStringAsync(uri);
var container = JsonConvert.DeserializeObject<CampaignTempleteStatus>(json);
if (container.status != "pending")
{
return container.status;
}
await Task.Delay(10000);
}
return "Timed out!";
}
Cancellation in managed threads explains how CancellationTokenSource and CancellationToken can be used to cancel threads, tasks and asynchronous functions. Many asynchronous methods already provide overloads that accept a CancellationToken parameter. The polling function could be modified to accept and check a canellation token :
public async Task<string> waitForCampaignLoadAsync(string uri,CancellationToken token=default)
{
var client=new HttpClient();
for(int i=0;i<30;i++)
{
var json = await client.GetStringAsync(uri);
var container = JsonConvert.DeserializeObject<CampaignTempleteStatus>(json);
if (container.status != "pending")
{
return container.status;
}
await Task.Delay(10000,token);
}
return "Timed out!";
}
A CancellationTokenSource can be used to call this method with an overall timeout of eg, 5 minutes :
var cts=new CancellationTokenSource(TimeSpan.FromMinutes(5));
try
{
var result=waitForCampaignLoadAsync(uri,cts.Token);
//Process the result ....
}
catch(OperationCancelledExcepction ex)
{
//Handle the timeout here
}
This code can be improved. For example, GetStringAsync() doesn't accept a cancellation token. The operation can be broken in two steps though, one call to GetAsync() with a cancellation token that waits for the server to send a result
and another to HttpContent.ReadAsStringAsync() to read the response, eg :
var response=await client.GetAsync(uri,token)
response.EnsureSuccessStatusCode();
var json=await response.Content.ReadAsStringAsync();
...
The first parameter of Timer is a TimerCallback delegate, which should return void
var stateTimer = new Timer(Repeat, autoEvent, 1000, (1000 * 60 * 10));
private void Repeat(object state)
{
....
}

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));

Measuring execution time of async code snippets

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");
}

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