【问题标题】:Reusable test code that waits for IO等待 IO 的可重用测试代码
【发布时间】:2015-11-07 15:03:04
【问题描述】:

我正在尝试在 WCF 公开的方法/服务上使用 async/await。一切正常,但我想模拟实际等待 IO 的服务方法,以便将服务调用注册到 IO 完成端口,并将线程放回线程池。

为了澄清,我只是在尝试确认 IO 完成端口的使用情况,并更好地了解实际发生的机制。

例如我的测试服务目前看起来像这样:

[ServiceContract]
public interface IHelloWorldService
{
    [OperationContract]
    Task<string> SayHello(string firstName, string lastName);
}


public class HelloWorldService : IHelloWorldService
{
    public async Task<string> SayHello(string firstName, string lastName)
    {
        string str = string.Format("Hello {0} {1}", firstName, lastName);
        return await Task.Factory.StartNew(() => str);
    }
}

我想在 SayHello() 中做一些事情以使该代码等待一些 IO,理想情况下,当我想模拟等待 IO 时,我可以复制/粘贴一般使用的代码模式。

通常 Thread.Sleep() 用于模拟长时间运行的任务,但我很确定这会使线程池线程进入睡眠状态,并且不会触发 IO 完成端口的使用。

【问题讨论】:

  • 你为什么不喜欢Task.Delay?它不会在 IOCP 线程上完成,但它也会阻塞调用线程。
  • 有趣。那么 Task.Delay() 会将线程返回到池中但不使用 IOCP?即它将使用一些非基于 IO 的替代方案来恢复服务调用?
  • @redcalx,不基于 IO,不。这是based on a timer
  • Task.Delay 使用System.Threading.Timer 类,该类又从ThreadPool 获取一个工作线程当计时器间隔到期时,调用TimerCallback 委托该线程(通过ThreadPool.QueueUserWorkItem,我相信)。整个事情都是基于定时器队列逻辑(我相信它为多个定时器使用了一个专用线程)。
  • 我的第一条评论中有错字,当然应该是“但它不会阻塞调用线程”。至于您希望继续使用 IOCP 线程,您应该能够使用异步命名管道(NamedPipeServerStreamNamedPipeClientStream)来模拟它。这可能比使用套接字更容易。

标签: c# .net wcf async-await iocp


【解决方案1】:

当我想模拟等待 IO 时,我可以复制/粘贴一般使用的代码模式。

通常 Thread.Sleep() 用于模拟长时间运行的任务

正如 cmets 中已经提到的,await Task.Delay(..)Thread.Sleep(..) 的异步等价物。它通常用于表示“未指定的异步操作”。

public async Task<string> SayHello(string firstName, string lastName)
{
    await Task.Delay(TimeSpan.FromSeconds(2));
    return string.Format("Hello {0} {1}", firstName, lastName);
}

但是,如果这是一个测试/模拟存根,那么您可能想要延迟一段真实的时间。异步测试存根通常与Task.FromResult(或Task.FromExceptionTask.FromCancelled同步实现:

public Task<string> SayHello(string firstName, string lastName)
{
    return Task.FromResult(string.Format("Hello {0} {1}", firstName, lastName));
}

但听起来你想强制异步。请注意,需要在单元测试中执行此操作的情况很少见,但它确实会不时出现。要在不占用宝贵时间的情况下强制异步,请使用Task.Yield

public async Task<string> SayHello(string firstName, string lastName)
{
    await Task.Yield();
    return string.Format("Hello {0} {1}", firstName, lastName);
}

【讨论】:

    猜你喜欢
    • 2012-02-04
    • 2014-10-20
    • 2016-11-30
    • 2020-02-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-24
    • 1970-01-01
    相关资源
    最近更新 更多