Concurrency in C# Cookbook 笔记
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 笔记的更多相关文章
- [C#] 《Concurrency in C# Cookbook》读书笔记(一)- 并发编程概述
并发编程概述 前言 我们经常在耳边听说一些关于高性能.并发和并行等名词,并且很多人都对并发编程有一些误解. 误解 1:并发就是多线程? 答:多线程只不过是并发编程的其中一种形式而已.并发编程的种类很多 ...
- Java Concurrency in Practice 读书笔记 第十章
粗略看完<Java Concurrency in Practice>这部书,确实是多线程/并发编程的一本好书.里面对各种并发的技术解释得比较透彻,虽然是面向Java的,但很多概念在其他语言 ...
- Python Cookbook 笔记--12章并发编程
<Python Cookbook(第3版)中文版> 1.队列queue的有些方法是线程不安全的,在多线程中最好别用 2.需要限制一段代码的并发访问量时,用信号量.不要把信号量当做普通的锁来 ...
- Java Concurrency in Practice 读书笔记 第二章
第二章的思维导图(代码迟点补上):
- java concurrency in practice读书笔记---ThreadLocal原理
ThreadLocal这个类很强大,用处十分广泛,可以解决多线程之间共享变量问题,那么ThreadLocal的原理是什么样呢?源代码最能说明问题! public class ThreadLocal&l ...
- Python Cookbook笔记
字符串:s.strip() 删除字符串开始和结尾的空白字符. s.lstrip() 删除左边的,s.rstrip() 删除右边的. 随机数:random.random() 生成0-1之间的数. ...
- Java Concurrency in Practice——读书笔记
Thread Safety线程安全 线程安全编码的核心,就是管理对状态(state)的访问,尤其是对(共享shared.可变mutable)状态的访问. shared:指可以被多个线程访问的变量 mu ...
- python cookbook 笔记三
分组: rows = [ {'address': '5412 N CLARK', 'date': '07/01/2012'}, {'address': '5148 N CLARK', 'date': ...
- python cookbook 笔记二
去重和排序: #coding=utf-8 def dedupe(items): seen = set() for item in items: if item not in seen: yield i ...
随机推荐
- CDOJ1927 爱吃瓜的伊卡洛斯(2) 【并查集】启发式合并+set
伊卡洛斯很爱吃西瓜.一次,他来到一个西瓜摊旁,发现水果摊有N个西瓜,西瓜有红色.黄色.绿色.蓝色……等等数不清的颜色. 伊卡洛斯很想知道知道一些信息,便于老板交谈了起来. 当老板的话的第一个字符为”A ...
- 二叉查找树及B-树、B+树、B*树变体
动态查找树主要有二叉查找树(Binary Search Tree),平衡二叉查找树(Balanced Binary Search Tree), 红黑树 (Red-Black Tree ), 都是典型的 ...
- 一起学Hive——创建内部表、外部表、分区表和分桶表及导入数据
Hive本身并不存储数据,而是将数据存储在Hadoop的HDFS中,表名对应HDFS中的目录/文件.根据数据的不同存储方式,将Hive表分为外部表.内部表.分区表和分桶表四种数据模型.每种数据模型各有 ...
- docker下搭建zipkin for mysql
docker pull openzipkin/zipkin 新建docker-compose.yml加入以下内容,自行修改. version: ' services: # The zipkin pro ...
- 006 python操作符
一:数值操作符 1.操作符 2.不同点 上面有了一个说法,这个 / 与其他的编程不同. 这个是精确的除法. 3.连续赋值 这种用法,第一次遇见,就记录下来. 4.注意点 重要的是要注意优先级的问题 二 ...
- CSU 1592 石子合并 (经典题)【区间DP】
<题目链接> 题目大意: 现在有n堆石子,第i堆有ai个石子.现在要把这些石子合并成一堆,每次只能合并相邻两个,每次合并的代价是两堆石子的总石子数.求合并所有石子的最小代价. Input ...
- Django之Models(一)
Django之Models(一) 目录 数据库的配置 模型代码与参数解析 ORM对单表的增删改查 查询的补充 数据库配置 django默认支持sqlite,mysql, oracle,postgres ...
- 实现简单的web框架
实现简单的web框架 流程: 服务端启动---服务端等待请求---客户端访问---服务端响应请求 代码: from wsgiref.simple_server import make_server # ...
- 从零搭建 ES 搜索服务(二)基础搜索
一.前言 上篇介绍了 ES 的基本概念及环境搭建,本篇将结合实际需求介绍整个实现过程及核心代码. 二.安装 ES ik 分析器插件 2.1 ik 分析器简介 GitHub 地址:https://git ...
- 治愈 JavaScript 疲态的学习计划【转载】
来源:伯乐在线 - Rose Wang 像其他人一样,最近我读了 Jose Aguinaga 的文章 <How it feels to learn JavaScript in 2016>. ...