此处参考自阿涛的博文:http://www.cnblogs.com/HelloMyWorld/p/5526914.html

一 自己定义

基本的思路:

net中异步操作由于是交给线程来实现,因此不可能真正想js那样将一个单线程上的任务移除:如

var id=setTimeout(fun,200);

if(id>0){

  clearTimeout(id);//将一个任务从单线程的任务栈中移除,自然就做到了真正的移除任务

}

但是在net中一个任务交给线程执行后,具体什么时候执行完成我们并不确定,就算是我们把线程终止掉,如果任务执行完了,且执行完后与之关联的处理函数关系任然建立,那么其处理函数一样会执行

那么对于net这样的现状,我们只好斩断与之关联的处理函数的关系,来达到取消一个任务的或者认为他超时

同样的原理,比如我们有一个搜索框,或者地图缩放来做一些事情,其实我们在输入框中输入一段文字是非常快的,假如我们以文本发生变化就去发起网络搜索,那么其实会发起n个字符的搜索请求;

但是实际上我们想要只是最后一次发起的请求而已,那么问题就来了,这些回来的数据谁先谁后都是随机的,也就自然的出现了结果乱七八糟,那么怎么办呢?

1 同步搜索

我们可以锁定ui界面让用户不再能够发起请求:当然是一个传统并非很友好的解决

如:点击搜索按钮,调用搜索程序发起搜索,锁住ui,等待结果返回,再解锁ui将操作交给用户;

2 延时处理

比如连续的触发任务执行,那么我们就让他在小于一段时间内的触发不发起真正的请求,这种办法也只是减少无用请求而已

如:我一直点搜索按钮一直点,是的一直点,但是当我到达比如200ms的才会发起请求,之前点的都没用;

3 取消无用的处理

比如我连续发起了10次请求但是,只要最后一次的,那么我把之前的就取消掉,请求其实已经发出,只是对于结果我们丢弃掉了

如:我一直点一直点一直点,发起了10次请求,但是我每次发起请求前就把上一次的丢弃掉,注意这里并不是真正让这个网络请求取消了,本质上是没有办法取消掉的,

我只是让回来的结果丢弃掉而已不做任何处理了,那么就算是我点了n次其实我也只取了我最后一次的结果,所以这样看起来合情合理,但是对于网络流量要求的app来说就很不科学了

4 将2和3结合起来

首先我们做一个延时处理比如200ms,当达到延时处理后再发起请求,但是有个特殊地方比如我在下一个200ms内又发起请求,此时结果并没有回来,那么我们将之前的任务取消掉就好了,这样也就相对友好的

处理了这些矛盾,这里兼顾了2和3的优缺点

以下是我改进的代码,让任务可以手动取消

封装的超时Task类

 public class TimeoutTask
{
#region 字段
private Action _action;
private CancellationToken _token;
private event AsyncCompletedEventHandler _asyncCompletedEvent;
private TaskCompletionSource<AsyncCompletedEventArgs> _tcs;
#endregion #region 静态方法
public static async Task<AsyncCompletedEventArgs> StartNewTask(Action action, CancellationToken token)
{
return await TimeoutTask.StartNewTask(action, token, Timeout.Infinite);
} public static async Task<AsyncCompletedEventArgs> StartNewTask(Action action, int timeout)
{
return await TimeoutTask.StartNewTask(action, CancellationToken.None, timeout);
} public static async Task<AsyncCompletedEventArgs> StartNewTask(Action action, CancellationToken token,
int timeout = Timeout.Infinite)
{
var task = new TimeoutTask(action, token, timeout); return await task.Run();
}
#endregion #region 构造 public TimeoutTask(Action action, int timeout) : this(action, CancellationToken.None, timeout)
{ } public TimeoutTask(Action action, CancellationToken token) : this(action, token, Timeout.Infinite)
{ } public TimeoutTask(Action action, CancellationToken token, int timeout = Timeout.Infinite)
{
_action = action; _tcs = new TaskCompletionSource<AsyncCompletedEventArgs>(); if (timeout != Timeout.Infinite)
{
var cts = CancellationTokenSource.CreateLinkedTokenSource(token);
cts.CancelAfter(timeout);
_token = cts.Token;
}
else
{
_token = token;
}
}
#endregion #region 公用方法 /// <summary>
/// 运行
/// </summary>
/// <returns></returns>
public async Task<AsyncCompletedEventArgs> Run()
{
_asyncCompletedEvent += AsyncCompletedEventHandler; try
{
using (_token.Register(() => _tcs.TrySetCanceled()))
{
ExecuteAction();
return await _tcs.Task.ConfigureAwait(false);
} }
finally
{
_asyncCompletedEvent -= AsyncCompletedEventHandler;
} } public void Cancel()
{
if (!_token.CanBeCanceled)
{
_tcs.TrySetCanceled();
}
}
#endregion #region 私有方法 /// <summary>
/// 执行Action
/// </summary>
private void ExecuteAction()
{
Task.Factory.StartNew(() =>
{
_action.Invoke(); OnAsyncCompleteEvent(null);
});
} /// <summary>
/// 异步完成事件处理
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void AsyncCompletedEventHandler(object sender, AsyncCompletedEventArgs e)
{
if (e.Cancelled)
{
_tcs.TrySetCanceled();
}
else if (e.Error != null)
{
_tcs.TrySetException(e.Error);
}
else
{
_tcs.TrySetResult(e);
}
} /// <summary>
/// 触发异步完成事件
/// </summary>
/// <param name="userState"></param>
private void OnAsyncCompleteEvent(object userState)
{
if (_asyncCompletedEvent != null)
{
_asyncCompletedEvent(this, new AsyncCompletedEventArgs(error: null, cancelled: false, userState: userState));
}
}
#endregion
} /// <summary>
/// 有返回值,可超时,可取消的Task
/// </summary>
/// <typeparam name="T"></typeparam>
public class TimeoutTask<T>
{
#region 字段
private Func<T> _func;
private CancellationToken _token;
private event AsyncCompletedEventHandler _asyncCompletedEvent;
private TaskCompletionSource<AsyncCompletedEventArgs> _tcs;
#endregion #region 静态方法
public static async Task<T> StartNewTask(Func<T> func, CancellationToken token,
int timeout = Timeout.Infinite)
{
var task = new TimeoutTask<T>(func, token, timeout); return await task.Run();
} public static async Task<T> StartNewTask(Func<T> func, int timeout)
{
return await TimeoutTask<T>.StartNewTask(func, CancellationToken.None, timeout);
} public static async Task<T> StartNewTask(Func<T> func, CancellationToken token)
{
return await TimeoutTask<T>.StartNewTask(func, token, Timeout.Infinite);
} #endregion #region 公用方法
/// <summary>
/// 运行Task
/// </summary>
/// <returns></returns>
public async Task<T> Run()
{
_asyncCompletedEvent += AsyncCompletedEventHandler; try
{
using (_token.Register(() => _tcs.TrySetCanceled()))
{
ExecuteFunc();
var args = await _tcs.Task.ConfigureAwait(false);
return (T)args.UserState;
} }
finally
{
_asyncCompletedEvent -= AsyncCompletedEventHandler;
} } public bool CanBeCanceled
{
get { return _token.CanBeCanceled; }
} public void Cancel()
{
if (!_token.CanBeCanceled)
{
_tcs.SetCanceled();
}
}
#endregion #region 构造
public TimeoutTask(Func<T> func, CancellationToken token) : this(func, token, Timeout.Infinite)
{ } public TimeoutTask(Func<T> func, int timeout = Timeout.Infinite) : this(func, CancellationToken.None, timeout)
{ } public TimeoutTask(Func<T> func, CancellationToken token, int timeout = Timeout.Infinite)
{
_func = func; _tcs = new TaskCompletionSource<AsyncCompletedEventArgs>(); if (timeout != Timeout.Infinite)
{
var cts = CancellationTokenSource.CreateLinkedTokenSource(token); cts.CancelAfter(timeout);
_token = cts.Token;
}
else
{
_token = token;
}
}
#endregion #region 私有方法 /// <summary>
/// 执行
/// </summary>
private void ExecuteFunc()
{
ThreadPool.QueueUserWorkItem(s =>
{
var result = _func.Invoke(); OnAsyncCompleteEvent(result);
});
} /// <summary>
/// 异步完成事件处理
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void AsyncCompletedEventHandler(object sender, AsyncCompletedEventArgs e)
{
if (e.Cancelled)
{
_tcs.TrySetCanceled();
}
else if (e.Error != null)
{
_tcs.TrySetException(e.Error);
}
else
{
_tcs.TrySetResult(e);
}
} /// <summary>
/// 触发异步完成事件
/// </summary>
/// <param name="userState"></param>
private void OnAsyncCompleteEvent(object userState)
{
if (_asyncCompletedEvent != null)
{
_asyncCompletedEvent(this, new AsyncCompletedEventArgs(error: null, cancelled: false, userState: userState));
}
}
#endregion
}

demo

 class Program
{
private static TimeoutTask<string> result; static void Main(string[] args)
{ ThreadMethod(); Console.WriteLine("启动完成");
Console.ReadLine();
} private async static void ThreadMethod()
{
// await TimeoutTask.StartNewTask(LongTimeWork, 6000);
// await TimeoutTask<string>.StartNewTask(LongTimeWork2, 2000);
try
{
for (int i = ; i < ; i++)
{ //我手动取消掉上一次的
if (result!=null)
{
try
{
//取消掉
result.Cancel();
}
catch (Exception er)
{
}
} result = new TimeoutTask<string>(LongTimeWork2); try
{
result.Run();
}
catch (Exception ee)
{ }
} Console.WriteLine(result);
}
catch (Exception ex)
{ }
} private static void LongTimeWork()
{
Thread.Sleep();
} private static string LongTimeWork2()
{
Thread.Sleep();
return "XXD";
} }

二 Task天生超时

什么是尝试超时,比如说连接数据库就有TryConnect尝试,在一些访问资源的时候经常用到,且Task本身也天生支持超时处理

var tokenSource = new CancellationTokenSource();
var token = tokenSource.Token;

var task=Task.Factory.StartNew(() =>
{
Thread.Sleep(3 * 1000);

}, token);

var timeout = task.Wait(4*1000,token);

if (timeout)
{

}

Wait会等待给定的时间,如果在给定的时间内已经完成那么,将返回true,意思是在指定的时间内完成了一个task,反之就认为超时了,这个也不乏一种超时处理

TPL异步并行编程之任务超时的更多相关文章

  1. TPL异步并行编程之取消任务

    TPL异步并行编程之简单使用 在上篇随笔里面说明了Task的使用,仅仅是简单使用,有时候把一个任务交给Task去执行,但是呢还是要管理下,比如说:我要叫这个任务停止了,不做了,任务取消了,或者超时了 ...

  2. TPL异步并行编程之简单使用

    并行编程一直是一个老生常谈的话题 在这里记录一下TPL编程,这在net4.0 微软就已经提供了多核时代下的并行库,其中最核心的最常用的也就是Task 一 Task是什么 Task可以简单的理解为一个线 ...

  3. TPL异步并行编程之回调

    Task是基于ThreadPool线程池基础上的高度异步多线程编程,如果有一天我希望一个需要长时间运行的Task,在被某些异常终止后还能回调一些代码就可以知道Task终止的原因了吧 是的,且看代码 p ...

  4. PHP socket 编程中的超时设置

    PHP socket 编程中的超时设置.网上找了半天也没找到.贴出来分享之:设置$socket 发送超时1秒,接收超时3秒: $socket = socket_create(AF_INET,SOCK_ ...

  5. Task C# 多线程和异步模型 TPL模型 【C#】43. TPL基础——Task初步 22 C# 第十八章 TPL 并行编程 TPL 和传统 .NET 异步编程一 Task.Delay() 和 Thread.Sleep() 区别

    Task C# 多线程和异步模型 TPL模型   Task,异步,多线程简单总结 1,如何把一个异步封装为Task异步 Task.Factory.FromAsync 对老的一些异步模型封装为Task ...

  6. linux网络编程中的超时设置

    1 下面是在网上找到的资料,先非常的感谢. 用setsockopt()来控制recv()与send()的超时 在send(),recv()过程中有时由于网络状况等原因,收发不能预期进行,而设置收发超时 ...

  7. C# 异步编程3 TPL Task 异步程序开发

    .Net在Framework4.0中增加了任务并行库,对开发人员来说利用多核多线程CPU环境变得更加简单,TPL正符合我们本系列的技术需求.因TPL涉及内容较多,且本系列文章为异步程序开发,所以本文并 ...

  8. connect socket的超时设置

    最近项目中,有个需求是检测某ip地址是否是通的,使用了socket的connect函数.但是,当ip地址写错的话,connect就会一直阻塞在那里,大概2.3分钟才能返回连接失败.这对于用户来说是不可 ...

  9. Java Socket编程详细解说

    Java Socket编程 JavaSocketServerSocket乱码超时 Java Socket编程 对于Java Socket编程而言,有两个概念,一个是ServerSocket,一个是So ...

随机推荐

  1. 转:什么是 HTTP Headers?

    什么是HTTP Headers HTTP是“Hypertext Transfer Protocol”的所写,整个万维网都在使用这种协议,几乎你在浏览器里看到的大部分内容都是通过http协议来传输的,比 ...

  2. 【翻译自mos文章】当指定asm disk 为FRA时,11.2.0.3的dbua hang住

    当指定asm disk 为FRA时.11.2.0.3的dbua hang住 来源于: 11.2.0.3 DBUA Hangs While Specifying ASM Disk To FRA (文档 ...

  3. mailcore -- Mail port

    以163为例的各个MailserverSSL协议port号和非SSL协议port号

  4. C# this关键字

    使用方式之一: this,在构造函数中使用. 当使用构造函数的重载时,可使用this关键字. //构造函数-重载 public Student(int id, string name, int age ...

  5. 为学Linux,我看了这些书

    为学Linux,我看了这些书   去年开始,抱着学习的态度开始了我的Linux学习,到现在,差不多一年了,收获很多,不敢说精通Linux,但是,还是对得起"略懂"这两个字的.这一年 ...

  6. vs2016 创建 vsto excel 文件项目的一个问题

    新工作需要些一个基于Excel开发一个工具,vs的 vsto 功能很好用,封装了基于开发office 开的一些工具.但是在实际使用时,创建项目总是报错,提示打开excel文件失败.项目是需要创建一个e ...

  7. Intent数据传递

    (1)首先是Activity的简单跳转: 1).Activity的切换一般是通过Intent来实现的,Intent是一个Activity到达另一个Activity的引路者,它描述了起点(当前Activ ...

  8. JVM调优总结(三)-基本垃圾回收算法

    可以从不同的的角度去划分垃圾回收算法: 按照基本回收策略分 引用计数(Reference Counting): 比较古老的回收算法.原理是此对象有一个引用,即增加一个计数,删除一个引用则减少一个计数. ...

  9. shell中exec解析(转)

    参考:<linux命令.编辑器与shell编程> <unix环境高级编程> exec和source都属于bash内部命令(builtins commands),在bash下输入 ...

  10. c语言实现atoi和itoa函数。

    首先看atoi函数: C语言库函数名: atoi 功 能: 把字符串转换成整型数. 名字来源:ASCII to integer 的缩写. 原型: int atoi(const char *nptr); ...