Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I use "Where" with an async predicate?

Tags:

I have an async predicate method like this:

private async Task<bool> MeetsCriteria(Uri address) {     //Do something involving awaiting an HTTP request. } 

Say I have a collection of Uris:

var addresses = new[] {     new Uri("http://www.google.com/"),     new Uri("http://www.stackoverflow.com/") //etc. }; 

I want to filter addresses using MeetsCriteria. I want to do this asynchronously; I want multiple calls to the predicate to run asynchronously, and I want to then wait for all of them to complete and produce the filtered result set. Unfortunately, LINQ doesn't appear to support asynchronous predicates, so something like this doesn't work:

var filteredAddresses = addresses.Where(MeetsCriteria); 

Is there a similarly convenient way to do this?

like image 305
Sam Avatar asked Feb 15 '13 07:02

Sam


People also ask

Does async run in parallel?

Asynchronous operations in parallelThe method async. parallel() is used to run multiple asynchronous operations in parallel.

Can we use async with void?

It's usually wrong to provide an async implementation (or override) of a void-returning method on an interface (or base class). Some events also assume that their handlers are complete when they return.

Does async await use thread pool?

The async and await keywords don't cause additional threads to be created. Async methods don't require multithreading because an async method doesn't run on its own thread. The method runs on the current synchronization context and uses time on the thread only when the method is active.

Do async functions run on another thread?

No, it does not. It MAY start another thread internally and return that task, but the general idea is that it does not run on any thread.


1 Answers

I think one of the reasons nothing like this is in the framework is that there is lots of possible variations and each choice will be the right one under certain circumstances:

  • Should the predicates execute in parallel, or in series?
    • If they execute in parallel, should they all execute at once, or should the degree of parallelism be limited?
    • If they execute in parallel, should the results be in the same order as the original collection, in the order of completion, or in undefined order?
      • If they should be returned in the order of completion, should there be some way to (asynchronously) get the results as they complete? (This would require the change of return type from Task<IEnumerable<T>> to something else.)

You said you want the predicates to execute in parallel. In that case, the simplest choice is to execute them all at once and return them in the order of completion:

static async Task<IEnumerable<T>> Where<T>(     this IEnumerable<T> source, Func<T, Task<bool>> predicate) {     var results = new ConcurrentQueue<T>();     var tasks = source.Select(         async x =>         {             if (await predicate(x))                 results.Enqueue(x);         });     await Task.WhenAll(tasks);     return results; } 

You could then use it like this:

var filteredAddresses = await addresses.Where(MeetsCriteria); 
like image 122
svick Avatar answered Oct 28 '22 07:10

svick