在本羊读大学的时候,Thread让本羊云里雾里,代码写的痛不欲生,真的是让本羊脑壳里不少“线”缠绕在一块儿。多线程
以后,Task让本羊代码写的飞起,甚至有时候根本不须要Task的时候仍是要写上,那样显得档次较高:多线程!充分利用CPU!niubility!异步
再以后,async/await语法糖横空出世,更让本羊欲罢不能!socket
然而,async
好东西吃多了总会腻的——吃货ide
常在河边走,哪有不湿鞋?——文艺青年性能
出来混老是要还的——“四道杠”骚年this
飙车一时爽,“全家”火葬场——老司机spa
扯远了,反正大概意思就是,async/await 也会有不爽的时候。.net
好比:UdpClient.ReceiveAsync()线程
某领导:只等待5秒,过期不候。这样比较节约性能。
——哎哟,颇有道理的样子,那就改改?
因而,本羊很快就找到了一个属性:UdpClient.Client.ReceiveTimeout
UdpClient.Client.ReceiveTimeout=5000;//领导说了只等5秒 <--注释在这里
var r=UdpClient.ReceiveAsync();
……(省略其余代码)
看到没,本羊还很善意的给代码加上了“注释”,方便其余小伙伴理解本羊的优雅的高深的简洁的代码。
而后拿起水杯,小小的抿了一口,伸出右手食指,轻轻的按下“F5”,左手在桌子上颇有节奏的敲了5下,哎哟,啥状况?
再敲5下,再敲5下,再敲5下……
好吧,本羊输了。
是时候打开MSDN了,原来,ReceiveTimeout这玩意儿只对同步方法有效,ReceiveAsync根本无论这Y的。
再研究研究?
通过一番刻苦钻研,新的代码来了:
var t=new CancellationTokenSource();//这玩意儿就是用来配合Task,作取消功能的
Task.Delay(5000, t.Token).ContinueWith(task =>
{
if (!task.IsCanceled && task.IsCompleted)//不是被取消并且已经完成
{
client.Close();//释放UdpClient
}
});//咱走着瞧(不会阻塞当前线程),5秒以后再来
try
{
var r=await client.ReceiveAsync();
return r;//返回结果
}
catch
{
throw new TimeoutException("过期不候!");//优雅的抛出错误提示
}
以上代码使用了很长一段时间,直到今天本羊又看到一些关于Task的文章,原来还有更优雅的实现方式!
很少说,上代码:
var t=new CancellationTokenSource();//又是这玩意儿
var r=await Task.WhenAny(client.ReceiveAsync(), Task.Delay(5000, t.Token)) as Task<UdpReceiveResult>;//仍是5秒,过期不候
if(r!=null)//若是是Delay先返回,是不能 as Task<UdpReceiveResult>的,r=null。
{
t.Cancel();//取消那个Delay,其实也能够不用处理,反正5秒后那家伙就本身去西天了
return r.Result;
}
else
{
client.Close();//释放UdpClient,否则仍是在ReceiveAsync
throw new TimeoutException("过期不候!");
}
再来一个:
var tasks=new Task[]{client.ReceiveAsync()};
var index=awati Task.Run(()=>
{
return Task.WaitAny(tasks, 5000);//返回完成的Task在集合中的序号
});//Wait[xxx]会阻塞线程,因此用一个Run包裹住
if(index==0)
{
return (tasks[0] as Task<UdpReceiveResult>).Result;
}
else
{
client.Close();
throw new TimeoutException("过期不候!");
}
又或者(重磅推荐):
var t = client.ReceiveAsync();
if (await Task.Run(() => { return t.Wait(5000); }))
{
return t.Result;
}
else
{
client.Close();
throw new TimeoutException("过期不候!");
}
CancellationTokenSource、Task.Delay(delay)都用不到了,爽歪歪~~
Wait[xxx]有多个重载,能够设置timeout、CancellationToken,不知道为啥When[xxx]不能设置?
最后放上Task的拓展方法:
1 public static class TaskExtension 2 { 3 /// <summary> 4 /// 异步等待 5 /// 任务完成当即返回,不然在指定时间后抛出TimeoutException 6 /// </summary> 7 /// <param name="task"></param> 8 /// <param name="timeout">等待时间(毫秒)</param> 9 /// <returns></returns> 10 public static async Task WaitAsync(this Task task, int timeout) 11 { 12 if (!await Task.Run(() => { return task.Wait(timeout); })) 13 throw new TimeoutException(); 14 } 15 16 /// <summary> 17 /// 异步等待 18 /// 任务完成当即返回,不然在指定时间后抛出TimeoutException 19 /// </summary> 20 /// <param name="task"></param> 21 /// <param name="timeout">等待时间(毫秒)</param> 22 /// <returns></returns> 23 public static async Task<T> WaitAsync<T>(this Task<T> task, int timeout) 24 { 25 if (await Task.Run(() => { return task.Wait(timeout); })) 26 return task.Result; 27 throw new TimeoutException(); 28 } 29 30 /// <summary> 31 /// 给“没法取消”的任务传入CancellationToken 32 /// </summary> 33 /// <param name="task">没法传入CancellationToken的任务</param> 34 /// <param name="token">CancellationToken</param> 35 /// <returns></returns> 36 public static async Task WaitAsync(this Task task, CancellationToken token) 37 { 38 if (!await Task.Run(() => { try { return task.Wait(-1, token); } catch { return false; } })) 39 throw new TaskCanceledException(); 40 } 41 42 /// <summary> 43 /// 给“没法取消”的任务传入CancellationToken 44 /// </summary> 45 /// <typeparam name="T">返回类型</typeparam> 46 /// <param name="task">没法传入CancellationToken的任务</param> 47 /// <param name="token">CancellationToken</param> 48 /// <returns></returns> 49 public static async Task<T> WaitAsync<T>(this Task<T> task, CancellationToken token) 50 { 51 if (await Task.Run(() => { try { return task.Wait(-1, token); } catch { return false; } })) 52 return task.Result; 53 throw new TaskCanceledException(); 54 } 55 56 /// <summary> 57 /// 封装“没法取消”的任务 58 /// </summary> 59 /// <typeparam name="T">返回类型</typeparam> 60 /// <param name="task">没法传入CancellationToken的任务</param> 61 /// <param name="watcher">可取消的无限等待任务[Task.Delay(-1,CancellationToken)]</param> 62 /// <returns></returns> 63 public static async Task<T> WaitAsync<T>(this Task<T> task, Task watcher) 64 { 65 var r = await Task.WhenAny(task, watcher); 66 if (r == task) 67 { 68 return task.Result; 69 } 70 throw new TaskCanceledException(); 71 } 72 73 74 public static CancellationTokenRegistration RegisterWidth<T>(this CancellationToken token, T state, Action<T> action) 75 { 76 return token.Register((p) => { action((T)p); }, state); 77 } 78 }
PS:其实本羊的工做一直是单枪匹马,意思就是公司里只有本羊一个程序猿,因此,某领导是没有的,其余小伙伴也是没有的,一切的一切都是本羊虚构的,包括大家。