Pausing for a Period of Time
Problem:
You need to (asynchronously) wait for a period of time. This can be useful when unit
testing or implementing retry delays. This solution can also be useful for simple time‐
outs.
Solution:
The Task type has a static method Delay that returns a task that completes after the
specified time。

This example defines a task that completes asynchronously, for use with unit testing.
When faking an asynchronous operation, it’s important to test at least synchronous
success and asynchronous success as well as asynchronous failure. This example returns
a task used for the asynchronous success case:

static async Task<T> DelayResult<T>(T result, TimeSpan delay)
{
await Task. Delay(delay);
return result;
}

This next example is a simple implementation of an exponential backoff, that is, a retry
strategy where you increase the delays between retries. Exponential backoff is a best
practice when working with web services to ensure the server does not get flooded with
retries.
For production code, I would recommend a more thorough solu‐
tion, such as the Transient Error Handling Block in Microsoft’s En‐
terprise Library; the following code is just a simple example of
Task.Delay usage.

static async Task<string> DownloadStringWithRetries(string uri)
{
using (var client = new HttpClient())
{
// Retry after 1 second, then after 2 seconds, then 4.
var nextDelay = TimeSpan. FromSeconds();
for (int i = ; i != ; ++i)
{
try
{
return await client. GetStringAsync(uri);
}
catch
{
}
await Task. Delay(nextDelay);
nextDelay = nextDelay + nextDelay;
}
// Try one last time, allowing the error to propogate.
return await client. GetStringAsync(uri);
}
}

This final example uses Task.Delay as a simple timeout; in this case, the desired se‐
mantics are to return null if the service does not respond within three seconds:

static async Task<string> DownloadStringWithTimeout(string uri)
{
using (var client = new HttpClient())
{
var downloadTask = client. GetStringAsync(uri);
var timeoutTask = Task. Delay();
var completedTask = await Task. WhenAny(downloadTask, timeoutTask);
if (completedTask == timeoutTask)
return null;
return await downloadTask;
}
}

Discussion
Task.Delay is a fine option for unit testing asynchronous code or for implementing
retry logic. However, if you need to implement a timeout, a CancellationToken is usu‐
ally a better choice.
See Also
Recipe 2.5 covers how Task.WhenAny is used to determine which task completes first.
Recipe 9.3 covers using CancellationToken as a timeout

2.2. Returning Completed Tasks
Problem
You need to implement a synchronous method with an asynchronous signature. This
situation can arise if you are inheriting from an asynchronous interface or base class
but wish to implement it synchronously. This technique is particularly useful when unit
testing asynchronous code, when you need a simple stub or mock for an asynchronous
interface.
Solution
You can use Task.FromResult to create and return a new Task<T> that is already com‐
pleted with the specified value

interface IMyAsyncInterface
{
Task<int> GetValueAsync();
}
class MySynchronousImplementation : IMyAsyncInterface
{
public Task<int> GetValueAsync()
{
return Task. FromResult();
}
}

2.3. Reporting Progress
Problem
You need to respond to progress while an asynchronous operation is executing.
Solution
Use the provided IProgress<T> and Progress<T> types. Your async method should
take an IProgress<T> argument; the T is whatever type of progress you need to report

static async Task MyMethodAsync(IProgress<double> progress = null)
{
double percentComplete = ;
while (! done)
{
...
if (progress != null)
progress. Report(percentComplete);
}
}

Calling code can use it as such:

static async Task CallMyMethodAsync()
{
var progress = new Progress<double>();
progress. ProgressChanged += (sender, args) =>
{
...
};
await MyMethodAsync(progress);
}

By convention, the IProgress<T> parameter may be null if the caller does not need
progress reports, so be sure to check for this in your async method.
Bear in mind that the IProgress<T>.Report method may be asynchronous. This means
that MyMethodAsync may continue executing before the progress is actually reported.
For this reason, it’s best to define T as an immutable type or at least a value type. If T is
a mutable reference type, then you’ll have to create a separate copy yourself each time
you call IProgress<T>.Report.
Progress<T> will capture the current context when it is constructed and will invoke its
callback within that context. This means that if you construct the Progress<T> on the
UI thread, then you can update the UI from its callback, even if the asynchronous
method is invoking Report from a background thread.
When a method supports progress reporting, it should also make a best effort to support
cancellation

If all the tasks have the same result type and they all complete successfully, then the
Task.WhenAll task will return an array containing all the task results:

Task task1 = Task. FromResult();
Task task2 = Task. FromResult();
Task task3 = Task. FromResult();
int[] results = await Task. WhenAll(task1, task2, task3);
// "results" contains { 3, 5, 7 }

There is an overload of Task.WhenAll that takes an IEnumerable of tasks; however, I
do not recommend that you use it. Whenever I mix asynchronous code with LINQ, I
find the code is clearer when I explicitly “reify” the sequence (i.e., evaluate the sequence,
creating a collection):

static async Task<string> DownloadAllAsync(IEnumerable<string> urls)
{
var httpClient = new HttpClient();
// Define what we're going to do for each URL.
var downloads = urls. Select(url => httpClient. GetStringAsync(url));
// Note that no tasks have actually started yet
// because the sequence is not evaluated.
// Start all URLs downloading simultaneously.
Task<string>[] downloadTasks = downloads. ToArray();
// Now the tasks have all started.
// Asynchronously wait for all downloads to complete.
string[] htmlPages = await Task. WhenAll(downloadTasks);
return string. Concat(htmlPages);
}
// Returns the length of data at the first URL to respond.
private static async Task<int> FirstRespondingUrlAsync(string urlA, string urlB)
{
var httpClient = new HttpClient();
// Start both downloads concurrently.
Task<byte[]> downloadTaskA = httpClient. GetByteArrayAsync(urlA);
Task<byte[]> downloadTaskB = httpClient. GetByteArrayAsync(urlB);
// Wait for either of the tasks to complete.
Task<byte[]> completedTask =
await Task. WhenAny(downloadTaskA, downloadTaskB);
// Return the length of the data retrieved from that URL.
byte[] data = await completedTask;
return data. Length;
}
static async Task<int> DelayAndReturnAsync(int val)
{
await Task. Delay(TimeSpan. FromSeconds(val));
return val;
}
static async Task AwaitAndProcessAsync(Task<int> task)
{
var result = await task;
Trace. WriteLine(result);
}
// This method now prints "1", "2", and "3".
static async Task ProcessTasksAsync()
{
// Create a sequence of tasks.
Task<int> taskA = DelayAndReturnAsync();
Task<int> taskB = DelayAndReturnAsync();
Task<int> taskC = DelayAndReturnAsync();
var tasks = new[] { taskA, taskB, taskC };
var processingTasks = (from t in tasks
select AwaitAndProcessAsync(t)). ToArray();
// Await all processing to complete
await Task. WhenAll(processingTasks);
}

Alternatively, this can be written as:

static async Task<int> DelayAndReturnAsync(int val)
{
await Task. Delay(TimeSpan. FromSeconds(val));
return val;
}
// This method now prints "1", "2", and "3".
static async Task ProcessTasksAsync()
{
// Create a sequence of tasks.
Task<int> taskA = DelayAndReturnAsync();
Task<int> taskB = DelayAndReturnAsync();
Task<int> taskC = DelayAndReturnAsync();
var tasks = new[] { taskA, taskB, taskC };
var processingTasks = tasks. Select(async t =>
{
var result = await t;
Trace. WriteLine(result);
}). ToArray();
// Await all processing to complete
await Task. WhenAll(processingTasks);
}

Concurrency in C# Cookbook 笔记的更多相关文章

  1. [C#] 《Concurrency in C# Cookbook》读书笔记(一)- 并发编程概述

    并发编程概述 前言 我们经常在耳边听说一些关于高性能.并发和并行等名词,并且很多人都对并发编程有一些误解. 误解 1:并发就是多线程? 答:多线程只不过是并发编程的其中一种形式而已.并发编程的种类很多 ...

  2. Java Concurrency in Practice 读书笔记 第十章

    粗略看完<Java Concurrency in Practice>这部书,确实是多线程/并发编程的一本好书.里面对各种并发的技术解释得比较透彻,虽然是面向Java的,但很多概念在其他语言 ...

  3. Python Cookbook 笔记--12章并发编程

    <Python Cookbook(第3版)中文版> 1.队列queue的有些方法是线程不安全的,在多线程中最好别用 2.需要限制一段代码的并发访问量时,用信号量.不要把信号量当做普通的锁来 ...

  4. Java Concurrency in Practice 读书笔记 第二章

    第二章的思维导图(代码迟点补上):

  5. java concurrency in practice读书笔记---ThreadLocal原理

    ThreadLocal这个类很强大,用处十分广泛,可以解决多线程之间共享变量问题,那么ThreadLocal的原理是什么样呢?源代码最能说明问题! public class ThreadLocal&l ...

  6. Python Cookbook笔记

    字符串:s.strip()  删除字符串开始和结尾的空白字符. s.lstrip() 删除左边的,s.rstrip()  删除右边的. 随机数:random.random()  生成0-1之间的数. ...

  7. Java Concurrency in Practice——读书笔记

    Thread Safety线程安全 线程安全编码的核心,就是管理对状态(state)的访问,尤其是对(共享shared.可变mutable)状态的访问. shared:指可以被多个线程访问的变量 mu ...

  8. python cookbook 笔记三

    分组: rows = [ {'address': '5412 N CLARK', 'date': '07/01/2012'}, {'address': '5148 N CLARK', 'date': ...

  9. python cookbook 笔记二

    去重和排序: #coding=utf-8 def dedupe(items): seen = set() for item in items: if item not in seen: yield i ...

随机推荐

  1. [转] JavaScript 之 ArrayBuffer

    JS里的ArrayBuffer 还记得某个晚上在做 canvas 像素级操作,发现存储像素的数据格式并不是Array类型,而是ArrayBuffer,心想这是什么鬼?后来查了一些资料,发现自己这半年来 ...

  2. cookie实现刷新不变化树形菜单

    通过设置cookie来保存树形菜单的状态,在页面加载时重新读取cookie来设置菜单. 菜单的HTML结构: <div class="treemenu"> <ul ...

  3. centos6.9编译安装nginx

    1.安装nginx所需的依赖包: yum -y install gcc gcc-c++ autoconf automake  zlib zlib-devel openssl openssl-devel ...

  4. 一起学Hadoop——TotalOrderPartitioner类实现全局排序

    Hadoop排序,从大的范围来说有两种排序,一种是按照key排序,一种是按照value排序.如果按照value排序,只需在map函数中将key和value对调,然后在reduce函数中在对调回去.从小 ...

  5. spark批量写写数据到Hbase中(bulkload方式)

    1:为什么大批量数据集写入Hbase中,需要使用bulkload BulkLoad不会写WAL,也不会产生flush以及split. 如果我们大量调用PUT接口插入数据,可能会导致大量的GC操作.除了 ...

  6. maven里面pom文件的各标签介绍

    由于maven在工作中经常使用,但是平时要记的知识点有点多,偶尔回头来看一些东西难免忘记,特此整理一篇笔记,方便大家搜索查询,也方便自己以后查询! 后续碰见其他的标签也会进行更新! maven的pom ...

  7. PAT (Basic Level) Practise - 害死人不偿命的(3n+1)猜想

    题目链接:https://www.patest.cn/contests/pat-b-practise/1001 卡拉兹(Callatz)猜想: 对任何一个自然数n,如果它是偶数,那么把它砍掉一半:如果 ...

  8. hibernate.properties not found

    在配置hibernate的主键生成策略的时候突然报出如下错误,寻找了很长时间,虽然不是什么严重的错误,但是希望可以警醒自己 问题: 11:26:21,611 INFO Version:37 - HHH ...

  9. POJ 1258 Agri-Net 【Prime】模板题

    题目链接>>> 题目大意:     给你N*N矩阵,表示N个村庄之间的距离.FJ要把N个村庄全都连接起来,求连接的最短距离(即求最小生成树).解析如下: #include <c ...

  10. RabbitMQ快速入门

    最近一段项目实践中大量使用了基于RabbitMQ的消息中间件,也积累的一些经验和思考,特此成文,望大家不吝赐教. 本文包括RabbitMQ基本概念.进阶概念.实践与思考等三部分,着重强调相关概念和基于 ...