Performance Guidelines
PFT1800: Consider using Any()
to determine whether an IEnumerable<T>
is empty
severity: 3
When a member or local function returns an IEnumerable<T>
or other collection class that does not expose a Count
property, use the Any()
extension method rather than Count()
to determine whether the collection contains items. If you do use Count()
, you risk that iterating over the entire collection might have a significant impact (such as when it really is an IQueryable<T>
to a persistent store).
Note: If you return an IEnumerable<T>
to prevent changes from calling code as explained in PFT1130, and you're developing in .NET 4.5 or higher, consider the new read-only classes.
PFT1820: Only use async
for low-intensive long-running activities
severity: 1
The usage of async
won't automagically run something on a worker thread like Task.Run
does. It just adds the necessary logic to allow releasing the current thread, and marshal the result back on that same thread if a long-running asynchronous operation has completed. In other words, use async
only for I/O bound operations.
PFT1825: Prefer Task.Run
or Task.Factory.StartNew
for CPU-intensive activities
severity: 1
If you do need to execute a CPU bound operation, use Task.Run
to offload the work to a thread from the Thread Pool. For long-running operations use Task.Factory.StartNew
with TaskCreationOptions.LongRunning
parameter to create a new thread. Remember that you have to marshal the result back to your main thread manually.
--
PFT1830: Beware of mixing up async
/await
with Task.Wait
severity: 1
await
does not block the current thread but simply instructs the compiler to generate a state-machine. However, Task.Wait
blocks the thread and may even cause deadlocks (see PFT1835).
PFT1835: Beware of async
/await
deadlocks in single-threaded environments
severity: 1
Consider the following asynchronous method:
private async Task GetDataAsync()
{
var result = await MyWebService.GetDataAsync();
return result.ToString();
}
Now when an ASP.NET MVC controller action does this:
public ActionResult ActionAsync()
{
var data = GetDataAsync().Result;
return View(data);
}
You end up with a deadlock. Why? Because the Result
property getter will block until the async
operation has completed, but since an async
method could automatically marshal the result back to the original thread (depending on the current SynchronizationContext
or TaskScheduler
) and ASP.NET uses a single-threaded synchronization context, they'll be waiting on each other. A similar problem can also happen on UWP, WPF or a Windows Store C#/XAML app. Read more about this here.