3

I'm experimenting with using async/await on WCF exposed methods/services. Everything works fine but I'd like to simulate the service method actually waiting for IO so that the service call will be registered with an IO completion port, and the thread put back into the thread pool.

To clarify, I'm just experimenting to confirm usage of IO completion ports and to get a better understanding of the mechanics of what's actually going on.

So e.g. my test service currently looks like this:

[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);
    }
}

I'd like to do something in SayHello() to cause that code to wait for some IO, ideally a code pattern I can copy/paste to use generally when I want to simulate waiting for IO.

Typically Thread.Sleep() is used to simulate a long running task, but I'm pretty sure that will put the thread pool thread to sleep and not trigger usage of an IO completion port .

abatishchev
  • 98,240
  • 88
  • 296
  • 433
redcalx
  • 8,177
  • 4
  • 56
  • 105
  • 2
    Why don't you like `Task.Delay`? It doesn't complete on an IOCP thread, but it does block the calling thread either. – noseratio Aug 14 '15 at 11:31
  • Interesting. So Task.Delay() will return the thread to the pool but not use an IOCP? i.e. it will use some none IO based alternative for resurrecting the service call? – redcalx Aug 14 '15 at 11:38
  • @redcalx, not IO-based, no. It's [based on a timer](https://github.com/Microsoft/referencesource/blob/master/mscorlib/system/threading/Tasks/Task.cs#L5853). – Thomas Levesque Aug 14 '15 at 11:43
  • 1
    `Task.Delay` uses `System.Threading.Timer` class, which in turn acquires a worker thread from `ThreadPool` *when the timer interval is due*, to call a `TimerCallback` delegate on that thread (via `ThreadPool.QueueUserWorkItem`, I believe). The whole thing is based upon timer queue logic (which I believe uses a dedicated thread for multiple timers). – noseratio Aug 14 '15 at 11:50
  • I don't think there's an API in .NET similar to `ThreadPool.QueueUserWorkItem` that would use an IOCP thread rather than a worker thread (check [this](http://stackoverflow.com/a/22475242/1768303) for some details). I don't think though that should matter for your test scenario. – noseratio Aug 14 '15 at 11:52
  • Yeh getting the thread back on the thread pool is ultimately the main thing I'm interested in, but I am eager to trigger use of IOCPs too - maybe the easiest way is to just call on to another WCF service with a delay within it. – redcalx Aug 14 '15 at 12:07
  • 1
    A typo in my 1st comment, it should of course be "but it does NOT block the calling thread". As to your desire to continue on an IOCP thread, you should be able to mock it with async named pipes (`NamedPipeServerStream`, `NamedPipeClientStream`). That'd probably be easier than using sockets. – noseratio Aug 15 '15 at 13:48
  • If you create an async function you express that processing your functions might be slow, but you also promise that you won't block the thread with any lengthy processing. On other words, whenever you do some lengthy processing you promise to call another Task, maybe do some other processing and await for the result of the Task when you need it. Keeping this in mind, you should not call System.Threading.Thread.Sleep but use Task.Delay(TimeSpan), which returns an awaitable Task. This ensures that even when you await this task, the calling thread is not blocked. – Harald Coppoolse Aug 24 '15 at 07:48

1 Answers1

3

a code pattern I can copy/paste to use generally when I want to simulate waiting for IO.

Typically Thread.Sleep() is used to simulate a long running task

As already mentioned in the comments, await Task.Delay(..) is the asynchronous equivalent of Thread.Sleep(..). It's commonly used to represent an "unspecified asynchronous operation".

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

However, if this is a test/mock stub, then you probably don't want to delay for a real amount of time. Asynchronous test stubs are generally implemented synchronously with Task.FromResult (or Task.FromException or Task.FromCancelled):

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

But it sounds like you want to force asynchrony. Note that needing to do this in a unit test is rare, but it does come up from time to time. To force asynchrony without taking up valuable time, use Task.Yield:

public async Task<string> SayHello(string firstName, string lastName)
{
    await Task.Yield();
    return string.Format("Hello {0} {1}", firstName, lastName);
}
Stephen Cleary
  • 437,863
  • 77
  • 675
  • 810