How to Get Awaitable Thread.Sleep

How to get awaitable Thread.Sleep?

The other answers suggesting starting a new thread are a bad idea - there's no need to do that at all. Part of the point of async/await is to reduce the number of threads your application needs.

You should instead use Task.Delay which doesn't require a new thread, and was designed precisely for this purpose:

// Execution of the async method will continue one second later, but without
// blocking.
await Task.Delay(1000);

This solution also has the advantage of allowing cancellation, if a cancellation token is provided. Example:

public async Task DoWork(CancellationToken token)
{
await Task.Delay(1000, token);
}

async/await deadlock caused by Thread.Sleep?

I see a couple red flags:

First, change Thread.Sleep(1000) to await Task.Delay(1000) so you're not blocking the thread. That may be part of your problem, although I don't see quite how at the moment.

Second, your Main method:

static void Main(string[] args)
{
Log();
Console.ReadKey();
}

There are two issues:

  1. Log() returns a Task that you are not observing to see when it has completed. You are probably getting a compiler warning about that.
  2. Your Main method is void, which means it can't use await.

The reason these are a problem is that the await keyword will return when it acts on an incomplete Task (and the rest of the method is signed up as the "continuation" to happen when after the waiting is done). Usually it returns its own Task object, but if it can't because the method is void, it returns nothing. But it still returns.

Because you're not doing anything with the Task returned from Log(), your Main method continues and you never know if it completes.

I see you are using Console.ReadKey() to keep the program running, which is "ok". But you could just change your Main method to async Task and await Log():

static async Task Main(string[] args)
{
await Log();
}

That is assuming you are using C# 7.1+, since that's when you could start returning a Task from Main().

Also, you are creating 100,000 threads but only allowing one to work at any one time. Why not just create a regular for or foreach loop and do them one at a time?

for (var i = 0; i < 100000; i++)
{
await logger.Log(i, new LogMessage() { Message = oneKBMessage, TimeStamp = DateTime.Now });
}

Then you don't even need the locks - at least for this specific use case. If there are other cases where you will call it from different threads, then keep the locks.

How does asynchronous programming work with threads when using Thread.Sleep()?

I see no evidence of multithreading background threads. What am I missing?

Possibly you are looking in the wrong place, or using the wrong tools. There's a handy property that might be of use to you, in the form of Thread.CurrentThread.ManagedThreadId. According to the docs,

A thread's ManagedThreadId property value serves to uniquely identify that thread within its process.

The value of the ManagedThreadId property does not vary over time

This means that all code running on the same thread will always see the same ManagedThreadId value. If you sprinkle some extra WriteLines into your code, you'll be able to see that your tasks may run on several different threads during their lifetimes. It is even entirely possible for some async applications to have all their tasks run on the same thread, though you probably won't see that behaviour in your code under normal circumstances.

Here's some example output from my machine, not guaranteed to be the same on yours, nor is it necessarily going to be the same output on successive runs of the same application.

00:00:00.0000030
* WriteWithSleep on thread 1 before await
* WriteWithoutSleep on thread 1 before first await
* WriteWithSleep on thread 4 after await
Delayed 1 seconds
00:00:01.0203244
* WriteWithoutSleep on thread 5 after first await
Delayed 3 second.
00:00:03.0310891
* WriteWithoutSleep on thread 6 after second await
Delayed 9 seconds.
00:00:09.0609263
Delayed 10 seconds
00:00:10.0257838
00:00:10.0898976

The business of running tasks on threads is handled by a TaskScheduler. You could write one that forces code to be single threaded, but that's not often a useful thing to do. The default scheduler uses a threadpool, and as such tasks can be run on a number of different threads.

Java - Thread.sleep VS Awaitility.await()

Despite your intention, I encourage you to give Awaitility and until() another try. The example below test the same thing in a single one-liner (albeit it is written in several lines for improved readability):

@Test
void test_refresh() {
Awaitility
.await()
.atMost(5, TimeUnit.SECONDS)
.until(() -> {
List<Trp> trpList = client.getAllTrps();
return !trpList.isEmpty();
});
}

For more fine grained control of the polling you can take a look at methods like pollInterval() and pollDelay().

When to use Task.Delay, when to use Thread.Sleep?

Use Thread.Sleep when you want to block the current thread.

Use await Task.Delay when you want a logical delay without blocking the current thread.

Efficiency should not be a paramount concern with these methods. Their primary real-world use is as retry timers for I/O operations, which are on the order of seconds rather than milliseconds.

Thread.Sleep x Task.Delay

They do quite different things.

Thread.Sleep causes the currently executing thread to just stop running for a given amount of time. It probably doesn't consume additional memory or do much processing, but the entire time it is sleeping it uses a system Thread, which is a limited resource. You could starve your application of threads, or cause another Thread to be created elsewhere, which has big performance impact. But, works great if that one thread is the only thing running on your computer.

Task.Delay creates a Task that will be dormant for the given amount of time and then finish. If you use in an asynchronous method, this allows you to return the thread to the caller, which can use it for something else until the timer is up. This is much more efficient when you have multiple threads, such as in a web server environment or doing a lot of database reads. However, you must use await, otherwise the task is created but then ignored, so it doesn't delay anything. And to use await, you must be in an asynchronous method in an asynchronous stack. You could call Wait() on the task, but that still locks the thread so might as well use Sleep at that point.

It looks like you have some worker threads of some kind. Better to make those tasks and they use .WaitAll on WhenAll or WhenAny to wait until one is actually finished.

Swift Concurrency - non-blocking sleep()?

Found it. There's a built-in method on Task (part of the Swift standard library) that offers this sleeping functionality to suspend the current task without blocking the thread.
The Swift runtime achieves this by adding a "suspension point" during runtime so the thread will be free to execute other code and will only return to the function when the task resumes.

"Tasks" are a construct offered by Swift's "structured concurrency" to aid with dispatching multiple workloads concurrently.
Anyone else interested can read more about it here.

func doWork() async {
// ...
await Task.sleep(for: .seconds(1)) // lightweight, does not block thread
// ...
}

Cannot await 'void'

Thread.sleep(3000) is not awaitable. Your method is async so ideal implementation will be await Task.Delay(3000)

Thread.Sleep is going to block your current thread and Task.Delay is going to delay logically without blocking your current thread.

Thread.sleep should not be used in asynchronous operation instead we should use Task.Delay(3000) and vice versa.



Related Topics



Leave a reply



Submit