Hi guys i'm trying to get some results from Task.Run but i cannot figure it how
I have multiple methods that i would like to run in parallel and extract result:
This is one of the methods
protected override async Task<IList<EducationDTO>> GetEmployeesEducation(int userId)
{
IList<EducationDTO> userEducation = await EducationService.GetEducationsByUserId(userId);
return userEducation.Count > 0 ? userEducation : null;
}
Here where all methods will be run in parallel
public async Task<DTOs.EmployeeDTO> GetEmployeeInfo(int userId)
{
EmployeeDTO employee = new EmployeeDTO();
Task task = Task.Run(() => {
Parallel.Invoke(
async () => { await GetEmployeeLanguages(userId); },
// ...
});
task.Wait();
/// extract result and process how ???
return employee;
}
I have multiple methods that i would like to run in parallel and extract result
Actually, you want to run them concurrently. "Parallel" implies CPU-bound code, but your code is I/O-bound.
So, don't use Parallel at all; it's the wrong tool here:
public async Task<DTOs.EmployeeDTO> GetEmployeeInfo(int userId)
{
EmployeeDTO employee = new EmployeeDTO();
// Start all tasks
var languagesTask = GetEmployeeLanguages(userId);
var educationsTask = GetEmployeesEducation(userId);
var outExperiencesTask = GetEmployeesOutExperience(userId);
var ubiExperiencesTask = GetEmployeesUbiExperience(userId);
// Asynchronously wait for them all to complete
await Task.WhenAll(languagesTask, educationsTask, outExperiencesTask, ubiExperiencesTask);
// Retrieve results
employee.Languages = await languagesTask;
employee.Educations = await educationsTask;
employee.OutExperiences = await outExperiencesTask;
employee.UbiExperiences = await ubiExperiencesTask;
return employee;
}
There's no use creating a task and immediately waiting for it, so drop the StartNew.
Also no need to first Wait and then fetch the Result, Result implicitly waits. And the method isn't asynchronous at all and you can drop async Task<> and directly return the EmployeeDTO...
So this is my finding
public async Task<DTOs.EmployeeDTO> GetEmployeeInfo(int userId)
{
EmployeeDTO employee = new EmployeeDTO();
Task<EmployeeDTO> task = Task.Factory.StartNew(() =>
{
Parallel.Invoke(
() => { employee.Languages = GetEmployeeLanguages(userId).Result; },
() => { employee.Educations = GetEmployeesEducation(userId).Result; },
() => { employee.OutExperiences = GetEmployeesOutExperience(userId).Result; },
() => { employee.UbiExperiences = GetEmployeesUbiExperience(userId).Result; });
return employee;
});
task.Wait();
return task.Result;
}
If you have any other suggestions, or a better approach please share. Thank you.
Related
After getting log inside subscribe method I want to call async function, but Subscribe function only takes Action<FilterLog>, so using async-await keyword is not possible.
How can I use await keyword inside this subscription ?
code example:
public static async Task GetLogsTokenTransfer_Observable_Subscription()
{
using(var client = new StreamingWebSocketClient("wss://mainnet.infura.io/ws"))
{
var filterTransfers = Event<TransferEventDTO>.GetEventABI().CreateFilterInput();
var subscription = new EthLogsObservableSubscription(client);
subscription.GetSubscriptionDataResponsesAsObservable().Subscribe(log =>
{
var decoded = Event<TransferEventDTO>.DecodeEvent(log);
if (decoded != null)
{
MyAsyncMethodHere(); // Can not use await keyword !!!!
}
});
await client.StartAsync();
await subscription.SubscribeAsync(filterTransfers);
await Task.Delay(TimeSpan.FromMinutes(1));
await subscription.UnsubscribeAsync();
await Task.Delay(TimeSpan.FromSeconds(5));
}
}
I'm not sure that this is the best approach but in my applications, i'm using Observable.FromAsync.
Smth like this:
subscription.GetSubscriptionDataResponsesAsObservable()
.Select(log => Observable.FromAsync(async () => {
await ProcessEvent(log);
}))
.Concat()
.Subscribe();
The Concat method is pretty important here, because it's ensures that the will be no overlapping in task execution
I am reading Concurrency in C# by Stephen Cleary in which there is an example that has puzzled me for a while.
Normally the LINQ Select method requires a lambda method that returns the value for the result collection.
In the book on page 30 there is an example where the lambda doesn't return anything, but nevertheless, the code compiles and runs fine:
static async Task<int> DelayAndReturnAsync(int val)
{
await Task.Delay(TimeSpan.FromSeconds(val));
return val;
}
static async Task ProcessTasksAsync()
{
// Create a sequence of tasks
Task<int> taskA = DelayAndReturnAsync(2);
Task<int> taskB = DelayAndReturnAsync(3);
Task<int> taskC = DelayAndReturnAsync(1);
var tasks = new[] { taskA, taskB, taskC };
var processingTasks = tasks.Select(async t =>
{
var result = await t;
Trace.WriteLine(result);
// Note: nothing is returned
}).ToArray();
// Await all processing to complete
await Task.WhenAll(processingTasks);
}
// Outputs:
// 1
// 2
// 3
The question is about this part:
var processingTasks = tasks.Select(async t =>
{
var result = await t;
Trace.WriteLine(result);
// Note: nothing is returned
}).ToArray();
Why is this? Is it a recommended approach?
UPDATE:
Where is this behaviour documented?
It's just like writing an async method that doesn't return a value, but uses a Task to indicate completion:
public async Task FooAsync()
{
Console.WriteLine("Before");
await Task.Delay(1000);
Console.WriteLine("After");
}
As an async anonymous function, that would be:
Func<Task> foo = async () =>
{
Console.WriteLine("Before");
await Task.Delay(1000);
Console.WriteLine("After");
};
I am trying to optimize this code to decrease the time taken to complete the forloop. In this case, CreateNotification() takes a long time and using async await does not improve performance as each asynchronous call is being awaited. I would like to use Task.WhenAll() to optimize the code. How can I do this?
foreach (var notification in notificationsInput.Notifications)
{
try
{
var result = await CreateNotification(notification);
notification.Result = result;
}
catch (Exception exception)
{
notification.Result = null;
}
notifications.Add(notification);
}
You can call Select on the collection whose elements you want to process in parallel, passing an asynchronous delegate to it. This asynchronous delegate would return a Task for each element that's processed, so you could then call Task.WhenAll on all these tasks. The pattern is like so:
var tasks = collection.Select(async (x) => await ProcessAsync(x));
await Task.WhenAll(tasks);
For your example:
var tasks = notificationsInput.Notifications.Select(async (notification) =>
{
try
{
var result = await CreateNotification(notification);
notification.Result = result;
}
catch (Exception exception)
{
notification.Result = null;
}
});
await Task.WhenAll(tasks);
This assumes that CreateNotification is thread-safe.
Update
You will need to install DataFlow to use this solution
https://www.nuget.org/packages/System.Threading.Tasks.Dataflow/
Depending on what CreateNotification is and whether you want to run this in parallel.
You could use a DataFlow ActionBlock, it will give you the best of both worlds if this is IO bound or Mix IO/CPU bound operations and let you run async and in parallel
public static async Task DoWorkLoads(NotificationsInput notificationsInput)
{
var options = new ExecutionDataflowBlockOptions
{
MaxDegreeOfParallelism = 50
};
var block = new ActionBlock<Something>(MyMethodAsync, options);
foreach (var notification in notificationsInput.Notifications)
block.Post(notification);
block.Complete();
await block.Completion;
}
...
public async Task MyMethodAsync(Notification notification)
{
var result = await CreateNotification(notification);
notification.Result = result;
}
Add pepper and salt to taste.
I think this ought to be equivalent to your code:
var notifications = new ConcurrentBag<Notification>();
var tasks = new List<Task>();
foreach (var notification in notificationsInput.Notifications)
{
var task = CreateNotification(notification)
.ContinueWith(t =>
{
if (t.Exception != null)
{
notification.Result = null;
}
else
{
notification.Result = t.Result;
}
notifications.Add(notification);
});
tasks.Add(task);
}
await Task.WhenAll(tasks);
.ContinueWith( will receive the completed/failed task from CreateNotification(, and is itself a task. We add the ContinueWith task to a list and use that in the WhenAll(.
I'm using a ConcurrentBag for notifications so that you can add from multiple threads safely. If you want to turn this into a regular list, you can call var regularListNotifications = notifications.ToList(); (assuming you have a using for LINQ).
I have an ASP.NET MVC application which needs to check if something exists at 3 remote API servers. The application passes an ID to each API and it returns either true or false. The code looks like this.
public class PingController
{
public async Task<bool> IsFound(int id)
{
var servers = new ['a.com', b.com', 'c.com'];
var result = await foundAtServers(id, servers);
return result;
}
private async Task<bool> foundAtServers(int id, string[] servers)
{
var tasks = from server in servers
select checkServer(id, server);
return await.Task.WhenAll(tasks.ToArray());
}
private async Task<bool> checkServer(id, server)
{
var request = new HttpRequestMessage(HttpMethod.Get, server+"/api/exists"+id);
var client = new HttpClient();
var task = await client.SendAsync(request);
var response = await task.Content.ReadAsStringAsync();
return bool.Parse(response);
}
}
This code currently checks all 3 APIs asynchronously but will wait until ALL of the HttpClient calls have completed before the MVC Action can return.
As soon as one API returns true I want to immediately return true on the Action, rather than wait for the other tasks to complete.
The C# Task class has .WaitAll and .WaitAny, but these won't work either. As I need to cancel the other HttpClient request, I presume I need to use a CancellationToken but I don't know how to use it with this structure.
Cheers.
If you want to immediately return, you can use Task.WhenAny instead of Task.WhenAll. This won't cancel the on-going tasks, but it will enable you to return as soon as possible:
private async Task<bool> FoundAtServersAsync(int id, string[] servers)
{
var tasks = (from server in servers
select checkServer(id, server)).ToList();
while (tasks.Count > 0)
{
var finishedTask = await Task.WhenAny(tasks);
if (finishedTask.Result)
{
return finishedTask.Result;
}
tasks.Remove(finishedTask);
}
return false;
}
This will discard the other tasks. This means that if any exception is thrown inside one of them, it will be swallowed.
Edit:
If you care about actually canceling the other tasks, consider passing your CancellationToken to the overload of SendAsync which takes one, and calling CancellationTokenSource.Cancel once a value is received. Note this will mean you'll also need to handle the OperationCanceledException they will throw.
If they don't matter, i'd simply discard them as above.
This problem is made easier by using the following method to take a sequence of tasks and order them based on when they are completed.
public static IEnumerable<Task<T>> Order<T>(this IEnumerable<Task<T>> tasks)
{
var taskList = tasks.ToList();
var taskSources = new BlockingCollection<TaskCompletionSource<T>>();
var taskSourceList = new List<TaskCompletionSource<T>>(taskList.Count);
foreach (var task in taskList)
{
var newSource = new TaskCompletionSource<T>();
taskSources.Add(newSource);
taskSourceList.Add(newSource);
task.ContinueWith(t =>
{
var source = taskSources.Take();
if (t.IsCanceled)
source.TrySetCanceled();
else if (t.IsFaulted)
source.TrySetException(t.Exception.InnerExceptions);
else if (t.IsCompleted)
source.TrySetResult(t.Result);
}, CancellationToken.None,
TaskContinuationOptions.PreferFairness,
TaskScheduler.Default);
}
return taskSourceList.Select(tcs => tcs.Task);
}
With this you can write:
public static async Task<bool> WhenAny(this IEnumerable<Task<bool>> tasks)
{
foreach (var task in tasks.Order())
if (await task)
return true;
return false;
}
You could wait for the first task to complete - if it's successful, return true immediately. Otherwise, wait for the next one to complete, and so on and so forth.
private async Task<bool> foundAtServers(int id, string[] servers)
{
var tasks = servers.Select(server => checkServer(id, server))
.ToList();
while(tasks.Any())
{
var task = await Task.WhenAny(tasks);
if(task.Result)
return true;
tasks.Remove(task);
}
return false;
}
I have an ASP.NET MVC 3 action method which accepts a HttpFileCollectionBase in the HTTP POST.
In this method, i need to resize and upload the image 3 times.
The action method currently looks like this:
public ActionResult ChangeProfilePicture()
{
var fileUpload = Request.Files[0];
ResizeAndUpload(fileUpload.InputStream, Size.Original);
ResizeAndUpload(fileUpload.InputStream, Size.Profile);
ResizeAndUpload(fileUpload.InputStream, Size.Thumb);
return Content("Success", "text/plain");
}
Basically this is a user profile page, where they change their profile pic. The upload happens via jQuery AJAX.
Now, how can i fire off the three ResizeAndUpload calls as asynchronous tasks, but not return the action result until all three tasks have completed?
Previously i've been using Task.Factory.StartNew to fire off asynchronous tasks, but that was when i didn't care about waiting for the result.
Any ideas?
One simple way of doing it, is using Join:
public ActionResult ChangeProfilePicture()
{
var fileUpload = Request.Files[0];
var threads = new Thread[3];
threads[0] = new Thread(()=>ResizeAndUpload(fileUpload.InputStream, Size.Original));
threads[1] = new Thread(()=>ResizeAndUpload(fileUpload.InputStream, Size.Profile));
threads[2] = new Thread(()=>ResizeAndUpload(fileUpload.InputStream, Size.Thumb));
threads[0].Start();
threads[1].Start();
threads[2].Start();
threads[0].Join();
threads[1].Join();
threads[2].Join();
return Content("Success", "text/plain");
}
It's possible though that the ResizeAndUpload method may be blocking somewhere (can't tell for sure without seeing the code) in which case it may be worthwhile to refactor those as well to make them async.
Also got it working using Task.Factory.StartNew, similar to #BFree's answer:
public ActionResult ChangeProfilePicture()
{
var fileUpload = Request.Files[0];
var threads = new Task[3];
threads[0] = Task.Factory.StartNew(()=>ResizeAndUpload(fileUpload.InputStream, Size.Original));
threads[1] = Task.Factory.StartNew(()=>ResizeAndUpload(fileUpload.InputStream, Size.Profile));
threads[2] = Task.Factory.StartNew(()=>ResizeAndUpload(fileUpload.InputStream, Size.Thumb));
Task.WaitAll(threads, 120000); // wait for 2mins.
return Content("Success", "text/plain");
}
Now sure if Thread or Task is better.
Different implementation that uses Task and ManualResetEvent
public ActionResult Sample()
{
var wh1 = new ManualResetEvent(false);
var wh2 = new ManualResetEvent(false);
var wh3 = new ManualResetEvent(false);
Task.Factory.StartNew(new Action<object>(wh =>
{
// DoSomething();
var handle = (ManualResetEvent)wh;
handle.Set();
}), wh1);
Task.Factory.StartNew(new Action<object>(wh =>
{
// DoSomething();
var handle = (ManualResetEvent)wh;
handle.Set();
}), wh2);
Task.Factory.StartNew(new Action<object>(wh =>
{
// DoSomething();
var handle = (ManualResetEvent)wh;
handle.Set();
}), wh3);
WaitHandle.WaitAll(new[] { wh1, wh2, wh3 });
return View();
}
hope this helps.
Here is my take on it, use a handy "Task.WaitAll" static method for waits..
public MyViewModel LoadData()
{
MyViewModel viewModel = null;
try
{
Task.Factory.StartNew(() =>
{
var task1 = Task<MyViewModel>.Factory.StartNew(() =>
{
return BuildMyViewModel(args);
});
var task2 = Task<ViewModel2>.Factory.StartNew(() =>
{
return BuildViewModel2(args);
});
var task3 = Task<ViewModel3>.Factory.StartNew(() =>
{
return BuildViewModel3(args);
});
Task.WaitAll(task1, task2, task3);
viewModel = task1.Result;
viewModel.ViewModel2 = task2.Result;
viewModel.ViewModel3 = task3.Result;
}).Wait();
}
catch (AggregateException ex)
{
System.Diagnostics.Trace.WriteLine(ex.StackTrace);
// ...
}
return viewModel;
}
There is also an async pattern for MVC actions, see this link:
http://msdn.microsoft.com/en-us/library/ee728598.aspx
you can still use Tasks, but don't need any special handling to allow the actions to execute async
You could make up a task, with child tasks. The parent task will complete, when all child tasks have completed.
Example:
public ActionResult ChangeProfilePicture()
{
var fileUpload = Request.Files[0];
Task.Factory.StartNew(() =>
{
Task.Factory.StartNew(() =>
ResizeAndUpload(fileUpload.InputStream, Size.Original),
TaskCreationOptions.AttachedToParent);
Task.Factory.StartNew(() =>
ResizeAndUpload(fileUpload.InputStream, Size.Profile),
TaskCreationOptions.AttachedToParent);
Task.Factory.StartNew(() =>
ResizeAndUpload(fileUpload.InputStream, Size.Thumb),
TaskCreationOptions.AttachedToParent);
}).Wait();
return Content("Success", "text/plain");
}