I'm coding a function that receives a condition to be met and a time out and it finishes when the condition is met or it times out.
This is what I have so far :
public static bool CheckWithTimeout(bool toBeChecked, int msToWait)
{
//var src = CancellationSource
var task = Task.Run(()=> {
while (!toBeChecked)
{
System.Threading.Thread.Sleep(25);
}
});
if (task.Wait(TimeSpan.FromMilliseconds(msToWait)))
return toBeChecked;
else
return false;
}
It works nice for simple bools but I would like to call it like:
CheckWithTimeout(myValue > 10, 500)
And it would return when myValue is bigger than ten, or 500 ms passed (and returns false in this case)
I checked and I think Func is what I need but.. I cannot find a proper example.
Additionally, if there is an already existing method to achieve this I'd definitely prefer it.
It's better to use separate tasks for the result and the waiting.
private async Task<bool> CheckWithTimeout(Func<bool> toBeChecked, int msToWait)
{
var waitTask = Task.Delay(msToWait);
var checkTask = Task.Run(toBeChecked);
await Task.WhenAny(waitTask, checkTask);
return checkTask.IsCompleted && await checkTask;
}
private async Task<bool> CheckWithTimeout<T>(Predicate<T> toBeChecked, T predicateParameter, int msToWait)
{
var waitTask = Task.Delay(msToWait);
var checkTask = Task.Run(() => toBeChecked(predicateParameter));
await Task.WhenAny(waitTask, checkTask);
return checkTask.IsCompleted && await checkTask;
}
That way you do not nescessary have to wait for the timeout.
(And Taks.Delay is better than Task.Wait because it doesn't block)
Edit: Example with function or predicate
If you use a simple bool parameter, it will be evaluated only once when the method is called. If you want to perform the evaluation multiple times, you need to use Func<bool>:
public static bool CheckWithTimeout(Func<bool> toBeChecked, int msToWait)
{
//var src = CancellationSource
var task = Task.Run(()=> {
while (!toBeChecked())
{
System.Threading.Thread.Sleep(25);
}
});
if (task.Wait(TimeSpan.FromMilliseconds(msToWait)))
return toBeChecked();
else
return false;
}
Now you can use a lambda to call the method:
CheckWithTimeout(() => myValue > 10, 500)
Or just create a method which returns a bool and pass its name in.
Related
I have the following code and I want that it is executed in the correct order, but I'm not sure if I use "await" correctly so that it is executed in the correct order.
The correct sequence should be:
1)Call GetTiltleData and get the CurrentCatalogVersion.
2)Call GetCatalogData to get the ItemID of the item that will get purchased.
3)Call MakePurchase to purchase the item.
4)Call GetInventoryList to get the player's current(after the purchase) inventory.
Am I using await correctly? Is my code executed in the correct order or is it possible that the code could be executed in a wrong order?
For example, is it possible that the code of GetCatalogData(); is executed before CurrentCatalogVersion = result.Result.Data["Catalogversion"]; ?
string CurrentCatalogVersion = "";
string ItemID = "";
int CurrentAmount = 0;
GetTiltleData();
GetCatalogData();
public async void GetTiltleData()
{
await ClientGetTitleData();
}
private async Task ClientGetTitleData()
{
var result = await PlayFabClientAPI.GetTitleDataAsync(new GetTitleDataRequest());
if (result.Result.Data == null || !result.Result.Data.ContainsKey("Catalogversion"))
Console.WriteLine(result.Error.GenerateErrorReport());
else
CurrentCatalogVersion = result.Result.Data["Catalogversion"];
}
public async void GetCatalogData()
{
await GetCatalog();
}
private async Task GetCatalog()
{
var result = await PlayFabClientAPI.GetCatalogItemsAsync(new GetCatalogItemsRequest()
{
CatalogVersion = CurrentCatalogVersion
});
foreach (var entry in result.Result.Catalog)
{
//For example, if you want to purchase a sword
if (entry.DisplayName == "Sword")
ItemID = entry.ItemId;
}
if (result.Error != null)
{
Console.WriteLine(result.Error.GenerateErrorReport());
}
else
{
Console.WriteLine("Listed items successful!");
await MakePurchase(ItemID);
}
}
private async Task MakePurchase(string itemid)
{
var result = await PlayFabClientAPI.PurchaseItemAsync(new PurchaseItemRequest()
{
CatalogVersion = CurrentCatalogVersion,
ItemId = ItemID,
Price = 100,
VirtualCurrency = "GO"
});
if (result.Error != null)
{
Console.WriteLine(result.Error.GenerateErrorReport());
}
else
{
Console.WriteLine("Purchase successful!");
await GetInventoryList();
}
}
private async Task GetInventoryList()
{
var result = await PlayFabClientAPI.GetUserInventoryAsync(new GetUserInventoryRequest());
//Get the current amount of the player's virtual currency after the purchase
CurrentAmount = result.Result.VirtualCurrency["GO"];
foreach (var entry in result.Result.Inventory)
{
//Get a list with the player's items after the purchase
Console.WriteLine($"{entry.DisplayName} {entry.UnitPrice} {entry.ItemId} {entry.ItemInstanceId}");
...
}
if (result.Error != null)
{
// Handle error if any
Console.WriteLine(result.Error.GenerateErrorReport());
}
else
{
Console.WriteLine("Got current inventory");
}
}
For example, is it possible that the code of GetCatalogData(); is executed before CurrentCatalogVersion = result.Result.Data["Catalogversion"]; ?
Yes, absolutely.
This is your calling code:
...
GetTiltleData();
GetCatalogData();
These are asynchronous methods, but you're not awaiting their results before continuing to the next instruction. This means both methods are fire and forget threads.
This means you have a race condition. Literally, you have 2 threads racing to finish their methods before the other. You have no guarantee which one will finish first, or how the CPU will prioritise their instructions. Because of how you've called those methods, you've essentially told the computer you don't care about the outcome of events.
Fastest way to ensure one method completes before the next one starts is to await them both. As Igor says, if you are going to use async methods, you should use async/await the entire way up and down your call stack.
string CurrentCatalogVersion = "";
string ItemID = "";
int CurrentAmount = 0;
await GetTiltleData(); // adding "await" to these 2 lines
await GetCatalogData();
In addition, PLEASE don't use async void in your method signatures. You should use async Task instead. See async/await - when to return a Task vs void?.
I have the following function which I want to convert to an async / non locking function.
Here is the function in its currenc form:
private static void BlockForResponse(ref bool localFlag)
{
int count = 0;
while (!localFlag)
{
Thread.Sleep(200);
if (count++ > 50) // 200 * 50 = 10 seconds
{
//timeout
throw new TimeOutException();
}
}
}
here is my attempt:
private static async Task BlockForResponse(ref bool localFlag)
{
int count = 0;
while (!localFlag)
{
await Task.Delay(200);
if (count++ > 50) // 200 * 50 = 10 seconds
{
//timeout
throw new TimeOutException();
}
}
}
however I get a compile error saying that async functions cant have ref or out parameters. However this is the core functionality of the function.
Is it possible to convert it to an async function?
Explanation of code:
I must admit this is an odd piece of code, let me try an explain what its trying to do:
so there is a 3rd party dll which I need to use. Which provides me with services, I sadly have no control over this dll.
The way it works,
I call a command in the dll providing it a callback function which it calls once it has finished the task.
I can only move on to what I want to do once I have the result from that call. hence the need fro this function.
I make the call to the dll, providing it with a call back function:
private bool _commandFlag = false;
private bool _commandResponse;
public async Task ExecuteCommand(string userId, string deviceId)
{
var link = await LinkProviderAsync.GetDeviceLinkAsync(deviceId, userId);
try
{
//execute command
if (link.Command(Commands.ConnectToDevice, CallBackFunction))
{
BlockForResponse(ref _commandFlag);
return; //Received a response
}
else
{ //Timeout Error
throw new ConnectionErrorException();
}
}
catch (Exception e)
{
throw e;
}
}
private void CallBackFunction(bool result)
{
_commandResponse = result;
_commandFlag = true;
}
The way it works, I call a command in the dll providing it a callback function which it calls once it has finished the task.
Then what you really want is to use TaskCompletionSource<T> to create a TAP method, something similar to this.
public static Task<bool> CommandAsync(this Link link, Commands command)
{
var tcs = new TaskCompletionSource<bool>();
if (!link.Command(command, result => tcs.TrySetResult(result)))
tcs.TrySetException(new ConnectionErrorException());
return tcs.Task;
}
With this extension method in place, your calling code is much cleaner:
public async Task ExecuteCommand(string userId, string deviceId)
{
var link = await LinkProviderAsync.GetDeviceLinkAsync(deviceId, userId);
var commandResponse = await link.CommandAsync(Commands.ConnectToDevice);
}
The problem with combining async and ref is that code inside an async function can run even after the method returns. So, if you did something like:
async Task BlockForResponseAsync(ref bool localFlag)
{
while (!localFlag)
{
...
}
}
void SomeMethod()
{
bool flag = false;
BlockForResponseAsync(ref flag); // note: no await here
}
Then the local variable flag would stop existing after SomeMethod() returned, but BlockForResponseAsync(), which has a reference to that variable, could still be executing. This is why the above code won't compile.
Basically, what you need is a closure, and in C#, ref doesn't create closures, but lambdas do. This means you can write your method like this:
async Task BlockForResponseAsync(Func<bool> localFlagFunc)
{
while (!localFlagFunc())
{
...
}
}
And use it like this:
bool flag = false;
var task = BlockForResponseAsync(() => flag);
// other code here
flag = true;
await task; // to make sure BlockForResponseAsync() completed successfully
This way also indicates your intention better. ref usually means something like: "give me a variable with some value, and I will change that value", which is not what you want here. On the other hand Func<T> means "give me something that I can use retrieve some value, potentially multiple times".
Imagine the following class:
public class Checker
{
public async Task<bool> Check() { ... }
}
Now, imagine a list of instances of this class:
IEnumerable<Checker> checkers = ...
Now I want to control that every instance will return true:
checkers.All(c => c.Check());
Now, this won't compile, since Check() returns a Task<bool> not a bool.
So my question is: How can I best enumerate the list of checkers?
And how can I shortcut the enumeration as soon as a checker returns false?
(something I presume All( ) does already)
"Asynchronous sequences" can always cause some confusion. For example, it's not clear whether your desired semantics are:
Start all checks simultaneously, and evaluate them as they complete.
Start the checks one at a time, evaluating them in sequence order.
There's a third possibility (start all checks simultaneously, and evaluate them in sequence order), but that would be silly in this scenario.
I recommend using Rx for asynchronous sequences. It gives you a lot of options, and it a bit hard to learn, but it also forces you to think about exactly what you want.
The following code will start all checks simultaneously and evaluate them as they complete:
IObservable<bool> result = checkers.ToObservable()
.SelectMany(c => c.Check()).All(b => b);
It first converts the sequence of checkers to an observable, calls Check on them all, and checks whether they are all true. The first Check that completes with a false value will cause result to produce a false value.
In contrast, the following code will start the checks one at a time, evaluating them in sequence order:
IObservable<bool> result = checkers.Select(c => c.Check().ToObservable())
.Concat().All(b => b);
It first converts the sequence of checkers to a sequence of observables, and then concatenates those sequences (which starts them one at a time).
If you do not wish to use observables much and don't want to mess with subscriptions, you can await them directly. E.g., to call Check on all checkers and evaluate the results as they complete:
bool all = await checkers.ToObservable().SelectMany(c => c.Check()).All(b => b);
And how can I shortcut the enumeration as soon as a checker returns false?
This will check the tasks' result in order of completion. So if task #5 is the first to complete, and returns false, the method returns false immediately, regardless of the other tasks. Slower tasks (#1, #2, etc) would never be checked.
public static async Task<bool> AllAsync(this IEnumerable<Task<bool>> source)
{
var tasks = source.ToList();
while(tasks.Count != 0)
{
var finishedTask = await Task.WhenAny(tasks);
if(! finishedTask.Result)
return false;
tasks.Remove(finishedTask);
}
return true;
}
Usage:
bool result = await checkers.Select(c => c.Check())
.AllAsync();
All wasn't built with async in mind (like all LINQ), so you would need to implement that yourself:
async Task<bool> CheckAll()
{
foreach(var checker in checkers)
{
if (!await checker.Check())
{
return false;
}
}
return true;
}
You could make it more reusable with a generic extension method:
public static async Task<bool> AllAsync<TSource>(this IEnumerable<TSource> source, Func<TSource, Task<bool>> predicate)
{
foreach (var item in source)
{
if (!await predicate(item))
{
return false;
}
}
return true;
}
And use it like this:
var result = await checkers.AllAsync(c => c.Check());
You could do
checkers.All(c => c.Check().Result);
but that would run the tasks synchronously, which may be very slow depending on the implementation of Check().
Here's a fully functional test program, following in steps of dcastro:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AsyncCheckerTest
{
public class Checker
{
public int Seconds { get; private set; }
public Checker(int seconds)
{
Seconds = seconds;
}
public async Task<bool> CheckAsync()
{
await Task.Delay(Seconds * 1000);
return Seconds != 3;
}
}
class Program
{
static void Main(string[] args)
{
var task = RunAsync();
task.Wait();
Console.WriteLine("Overall result: " + task.Result);
Console.ReadLine();
}
public static async Task<bool> RunAsync()
{
var checkers = new List<Checker>();
checkers
.AddRange(Enumerable.Range(1, 5)
.Select(i => new Checker(i)));
return await checkers
.Select(c => c.CheckAsync())
.AllAsync();
}
}
public static class ExtensionMethods
{
public static async Task<bool> AllAsync(this IEnumerable<Task<bool>> source)
{
var tasks = source.ToList();
while (tasks.Count != 0)
{
Task<bool> finishedTask = await Task.WhenAny(tasks);
bool checkResult = finishedTask.Result;
if (!checkResult)
{
Console.WriteLine("Completed at " + DateTimeOffset.Now + "...false");
return false;
}
Console.WriteLine("Working... " + DateTimeOffset.Now);
tasks.Remove(finishedTask);
}
return true;
}
}
}
Here's sample output:
Working... 6/27/2014 1:47:35 AM -05:00
Working... 6/27/2014 1:47:36 AM -05:00
Completed at 6/27/2014 1:47:37 AM -05:00...false
Overall result: False
Note that entire eval ended when exit condition was reached, without waiting for the rest to finish.
As a more out-of-the-box alternative, this seems to run the tasks in parallel and return shortly after the first failure:
var allResult = checkers
.Select(c => Task.Factory.StartNew(() => c.Check().Result))
.AsParallel()
.All(t => t.Result);
I'm not too hot on TPL and PLINQ so feel free to tell me what's wrong with this.
I've got a caching class that uses cold (unstarted) tasks to avoid running the expensive thing multiple times.
public class AsyncConcurrentDictionary<TKey, TValue> : System.Collections.Concurrent.ConcurrentDictionary<TKey, Task<TValue>>
{
internal Task<TValue> GetOrAddAsync(TKey key, Task<TValue> newTask)
{
var cachedTask = base.GetOrAdd(key, newTask);
if (cachedTask == newTask && cachedTask.Status == TaskStatus.Created) // We won! our task is now the cached task, so run it
cachedTask.Start();
return cachedTask;
}
}
This works great right up until your task is actually implemented using C#5's await, ala
cache.GetOrAddAsync("key", new Task(async () => {
var r = await AsyncOperation();
return r.FastSynchronousTransform();
}));)`
Now it looks like TaskExtensions.Unwrap() does exactly what I need by turning Task<Task<T>> into a Task<T>, but it seems that wrapper it returns doesn't actually support Start() - it throws an exception.
TaskCompletionSource (my go to for slightly special Task needs) doesn't seem to have any facilities for this sort of thing either.
Is there an alternative to TaskExtensions.Unwrap() that supports "cold tasks"?
All you need to do is to keep the Task before unwrapping it around and start that:
public Task<TValue> GetOrAddAsync(TKey key, Func<Task<TValue>> taskFunc)
{
Task<Task<TValue>> wrappedTask = new Task<Task<TValue>>(taskFunc);
Task<TValue> unwrappedTask = wrappedTask.Unwrap();
Task<TValue> cachedTask = base.GetOrAdd(key, unwrappedTask);
if (cachedTask == unwrappedTask)
wrappedTask.Start();
return cachedTask;
}
Usage:
cache.GetOrAddAsync(
"key", async () =>
{
var r = await AsyncOperation();
return r.FastSynchronousTransform();
});
I'm trying to implement this trivial task of listing all objects in an AmazonS3 bucket with paged requests asynchronously in C#4. I have it working in C#5 using the following snippet:
var listRequest = new ListObjectsRequest().WithBucketName(bucketName);
ListObjectsResponse listResponse = null;
var list = new List<List<S3Object>>();
while (listResponse == null || listResponse.IsTruncated)
{
listResponse = await Task<ListObjectsResponse>.Factory.FromAsync(
client.BeginListObjects, client.EndListObjects, listRequest, null);
list.Add(listResponse.S3Objects);
if (listResponse.IsTruncated)
{
listRequest.Marker = listResponse.NextMarker;
}
}
return list.SelectMany(l => l);
I'm calling the BeginListObjects/EndListObjects pair asynchronously, but I have to repeat that call every time the response says it's truncated. This piece of code works for me.
However, I now want to do this in C#4's TPL, where I don't have the luxury of using async/await and want to understand if this can be done using continuations.
How do I do this same thing in C#4?
Okay, so rather than putting the items into a list with each task/continuation it's easier in a non-await model to just have each task/continuation return the entire sequence. Given that, I used the following helper method to add each one's iterative results onto the aggregate total.
public static Task<IEnumerable<T>> Concat<T>(Task<IEnumerable<T>> first
, Task<IEnumerable<T>> second)
{
return Task.Factory.ContinueWhenAll(new[] { first, second }, _ =>
{
return first.Result.Concat(second.Result);
});
}
Next, I used the follow method to take a task of a single result and turn it into a task of a sequence (containing just that one item).
public static Task<IEnumerable<T>> ToSequence<T>(this Task<T> task)
{
var tcs = new TaskCompletionSource<IEnumerable<T>>();
task.ContinueWith(_ =>
{
if (task.IsCanceled)
tcs.SetCanceled();
else if (task.IsFaulted)
tcs.SetException(task.Exception);
else
tcs.SetResult(Enumerable.Repeat(task.Result, 1));
});
return tcs.Task;
}
Note here that you have some fields/locals not defined; I'm assuming you can add them to the appropriate method without difficulty.
private Task<IEnumerable<S3Object>> method(object sender, EventArgs e)
{
ListObjectsResponse listResponse = null;
return Task<ListObjectsResponse>.Factory.FromAsync(
client.BeginListObjects, client.EndListObjects, listRequest, null)
.ToSequence()
.ContinueWith(continuation);
}
Here is where the real magic happens. Basically,
public Task<IEnumerable<S3Object>> continuation(Task<IEnumerable<S3Object>> task)
{
if (task.Result == null) //not quite sure what null means here//may need to edit this recursive case
{
return Task<ListObjectsResponse>.Factory.FromAsync(
client.BeginListObjects, client.EndListObjects, listRequest, null)
.ToSequence()
.ContinueWith(continuation);
}
else if (task.Result.First().IsTruncated)
{
//if the results were trunctated then concat those results with
//TODO modify the request marker here; either create a new one or store the request as a field and mutate.
Task<IEnumerable<S3Object>> nextBatch = Task<ListObjectsResponse>.Factory.FromAsync(
client.BeginListObjects, client.EndListObjects, listRequest, null)
.ToSequence()
.ContinueWith(continuation);
return Concat(nextBatch, task);//recursive continuation call
}
else //if we're done it means the existing results are sufficient
{
return task;
}
}