我应该为同步方法公开异步包装器吗?
对于这样的问题,我的简短回答是“不”。
例如,考虑一个同步方法Sleep,它在N毫秒内不返回:
public void Sleep(int millisecondsTimeout)
{
Thread.Sleep(millisecondsTimeout);
}
现在,考虑创建异步版本的需求,这样返回的Task在N毫秒内不会完成。这里有一个可能的实现,简单地用Task包装Sleep。运行命令创建一个SleepAsync:
public Task SleepAsync(int millisecondsTimeout)
{
return Task.Run(() => Sleep(millisecondsTimeout));
}
这是另一个不使用Sleep的,而是重写实现以消耗更少的资源:
public Task SleepAsync(int millisecondsTimeout)
{
TaskCompletionSource<bool> tcs = null;
var t = new Timer(delegate { tcs.TrySetResult(true); }, null, –1, -1);
tcs = new TaskCompletionSource<bool>(t);
t.Change(millisecondsTimeout, -1);
return tcs.Task;
}
这两种实现都提供相同的基本行为,都在超时过期后完成返回的任务。然而,从可伸缩性的角度来看,后者更具可伸缩性。前一种实现在等待时间期间从线程池中消耗一个线程,而后一种实现仅依赖于一个有效的计时器,在等待时间到期时向Task发出信号。
场景
1.在服务器开发中,不要用异步方法包装同步方法,因为这只是转移了执行任务的线程,并不能带来实际性的性能提升,而且线程调度还会带来一定的开销
2.在桌面开发中,使用异步方法包装同步方法是可行的,因为某些操作会长期执行而阻塞UI。使用异步将UI线程转移到线程池执行,这点开销是值得的。
3.在桌面开发中,使用异步方法包装同步方法对并行性也很重要。 并行编程就是把一个问题分割成可以并发处理的子问题。 如果你将一个问题分割成子问题,然后串行地处理每个子问题,就没有任务并行可言,因为是在一个线程上处理。 相反,如果你通过异步调用将一个子问题转移到另一个线程,你就可以并发地处理这些子问题。 这样就可以通过包装来实现并行性。
4.平常我们在封装接口时,如果一个方法没有异步实现,就不要再去增加一个Task.Run包装的异步实现。因为这对调用者来说,并不友好。是否需要包装成异步,应该由调用者决定,我们直接给出同步实现的接口即可。
5. 好的异步,是可以充分利用服务器硬件资源,而不是换个方式阻塞
标签:异步,Task,C#,millisecondsTimeout,包装,线程,中能,Sleep From: https://www.cnblogs.com/kkbk/p/17799799.html