C# 如何获得与Task相当的<;T>;在.NET3.5中?
我有一些代码正在使用C# 如何获得与Task相当的<;T>;在.NET3.5中?,c#,asynchronous,.net-3.5,task-parallel-library,task,C#,Asynchronous,.net 3.5,Task Parallel Library,Task,我有一些代码正在使用任务,它将从串行读取操作返回的结果延迟很短时间,如下所示: void ReturnResponseAfterAShortDelay() { if (delayedResponseCancellationTokenSource != null) delayedResponseCancellationTokenSource.Cancel(); // Cancel any pending operations and start a new one.
任务
,它将从串行读取操作返回的结果延迟很短时间,如下所示:
void ReturnResponseAfterAShortDelay()
{
if (delayedResponseCancellationTokenSource != null)
delayedResponseCancellationTokenSource.Cancel(); // Cancel any pending operations and start a new one.
delayedResponseCancellationTokenSource = new CancellationTokenSource();
log.InfoFormat("Deferring response for {0} ms", Settings.Default.TimeoutMs);
Task.Delay(Properties.Settings.Default.TimeoutMs, delayedResponseCancellationTokenSource.Token)
.ContinueWith((continuation) => ReturnWhateverHasArrived(), TaskContinuationOptions.NotOnCanceled)
.Start();
}
这段代码的思想是在指定的时间间隔内没有新字符到达时返回结果
然而,由于我无法控制的因素,我必须使用.NET3.5,这阻止了我使用任务
,因此我必须以某种方式重构此代码
如果不使用任务
,如何获得相同的结果
澄清
虽然我展示的特定代码恰好是一个定时延迟,但我的使用并不限于延迟。在其他情况下,我可能希望立即开始一些“长时间运行”的轮询任务。典型情况是I/O绑定操作,例如,定期查询连接到串行端口的设备,然后在满足某些条件时引发事件。使用线程池执行该方法: 为Servy编辑: 任务并行库和PLINQ的默认调度程序使用.NET Framework线程池对工作进行排队和执行。在.NET Framework 4中,线程池使用System.Threading.Tasks.Task类型提供的信息来有效支持并行任务和查询通常表示的细粒度并行性(短期工作单元) 编辑2(由于负面反馈): 此代码完全符合OP的要求:
void ReturnResponseAfterAShortDelay(WaitHandle cancellationToken)
{
log.InfoFormat("Deferring response for {0} ms", Settings.Default.TimeoutMs);
ThreadPool.RegisterWaitForSingleObject(cancellationToken,
() =>
{
if (!cancellationToken.WaitOne(0))
{
ReturnWhateverHasArrived();
}
},
null, Settings.Default.TimeoutMs, true);
}
使用定时器
(这实际上是延迟
在内部实现的方式)
private static HashSet timers=new HashSet();
public static void ExecuteAfter(操作、时间间隔延迟)
{
计时器=空;
计时器=新系统。线程。计时器(s=>
{
动作();
timer.Dispose();
锁(计时器)
定时器。移除(定时器);
},null,(长)delay.total毫秒,Timeout.Infinite);
锁(计时器)
定时器。添加(定时器);
}
对于您的编辑,如果您使用的是构建在异步IO之上的异步应用程序,那么该异步IO将已经公开一些异步方法。它可以是基于事件的模型,可以接受回调,可以使用
IAsyncResult
,等等。Task
是异步编程的另一种可能的方法,您当然可以将任何方法转换为任何其他方法,如果您喜欢的话,但一般来说,人们倾向于坚持使用他们正在执行的底层IO使用的任何方法,除非他们有令人信服的理由这样做。您可以通过NuGet使用以下软件包之一:
- 您可以在NuGet上使用该包。此包有一个强名称,是.NET 4的.NET任务并行库的.NET 3.5后端口,该库包含在被动扩展中
- 您可以在NuGet上使用该包。此替代实现使用Mono代码库而不是Microsoft实现。请注意,此包中包含的程序集没有强名称,因此如果库使用强名称,则这不是一个选项
IEnumerable
和yield
。它允许实现一个异步状态机,类似于C#5.0的async/await
。通过这种方式,您可以为异步逻辑保留方便的线性代码流。所有的C语言代码控制语句都可以工作(此外,您不能从内部执行返回try/catch
)
例如,带有计时器的控制台应用程序:
using System;
using System.Collections;
using System.Threading;
namespace ConsoleApplication_22516303
{
class Program
{
class AsyncLogic
{
public EventHandler Completed = delegate { };
IEnumerable WorkAsync(Action nextStep)
{
using (var timer = new System.Threading.Timer(_ => nextStep()))
{
timer.Change(0, 500);
var tick = 0;
while (tick < 10)
{
// resume upon next timer tick
yield return Type.Missing;
Console.WriteLine("Tick: " + tick++);
}
}
this.Completed(this, EventArgs.Empty);
}
public void Start()
{
IEnumerator enumerator = null;
Action nextStep = () => enumerator.MoveNext();
enumerator = WorkAsync(nextStep).GetEnumerator();
nextStep();
}
}
static void Main(string[] args)
{
var mre = new ManualResetEvent(false);
var asyncLogic = new AsyncLogic();
asyncLogic.Completed += (s, e) => mre.Set();
asyncLogic.Start();
mre.WaitOne();
Console.WriteLine("Completed, press Enter to exit");
Console.ReadLine();
}
}
}
使用系统;
使用系统集合;
使用系统线程;
命名空间控制台应用程序\u 22516303
{
班级计划
{
类异步逻辑
{
public EventHandler Completed=委托{};
IEnumerable WorkAsync(操作下一步)
{
使用(var timer=new System.Threading.timer(=>nextStep()))
{
定时器。改变(0,500);
var tick=0;
而(勾选<10)
{
//在下一个计时器滴答声时继续
收益率返回类型。缺少;
Console.WriteLine(“Tick:+Tick++”);
}
}
this.Completed(this,EventArgs.Empty);
}
公开作废开始()
{
IEnumerator枚举数=null;
Action nextStep=()=>enumerator.MoveNext();
enumerator=WorkAsync(nextStep).GetEnumerator();
下一步();
}
}
静态void Main(字符串[]参数)
{
var mre=新手动重置事件(错误);
var asynchlogic=new asynchlogic();
asyncLogic.Completed+=(s,e)=>mre.Set();
asynchlogic.Start();
韦通先生();
Console.WriteLine(“已完成,按Enter键退出”);
Console.ReadLine();
}
}
}
任何事件都可以用调用nextStep
的处理程序包装,类似于上面的计时器回调。事件发生时,代码将在相应的收益返回后继续执行
有相当多的实现利用了这种方法,例如 根据@Servy的答案,对我的答案稍加修改:
ExecuteAfter(() => MessageBox.Show("hi"), 1000 );
代码:ExecuteAfter(() => MessageBox.Show("hi"), 1000 );
public static void ExecuteAfter(Action action, int milliseconds)
{
System.Threading.Timer timer = null;
timer = new System.Threading.Timer(s =>
{
action();
timer.Dispose();
lock (timers)
timers.Remove(timer);
}, null, milliseconds, UInt32.MaxValue-10);
lock (timers)
timers.Add(timer);
}
private static HashSet<System.Threading.Timer> timers = new HashSet<System.Threading.Timer>()