Is it valid to wake a Rust future while it's being polled? - asynchronous

I'd like to be able to sleep my future for a single "frame" so that other work can happen. Is this a valid implementation of this idea?
use std::future::Future;
use std::task::{Context, Poll};
use std::pin::Pin;
struct Yield {
yielded: bool,
}
impl Future for Yield {
type Output = ();
fn poll(mut self: Pin<&mut Self>, ctx: &mut Context) -> Poll<()> {
if self.yielded {
Poll::Ready(())
} else {
self.yielded = true;
// This is the part I'm concerned about
ctx.waker().wake_by_ref();
Poll::Pending
}
}
}
Specifically, my concern is that the context won't "notice" the wake_by_ref call if it's made before the poll returns Pending. Does the interface contract of poll make any guarantees about this task being immediately re-polled when executed in this way?

TL;DR: Your code is valid.
Based on the contract for the waker, it has to poll your future one more time. Otherwise, it is possible to have a race condition between the Future::poll call and the counterpart of the future which actually does some work.
Let's take a look at an example:
impl Future for Foo {
type Output = ();
fn poll(self: Pin<&mut Self>, ctx: &mut Context) -> Poll<()> {
let result = communicate_with_worker(ctx); // returns false
// <-- Time point (1)
return match result {
true => Poll::Pending,
false => Poll::Ready(()),
};
}
}
At time point (1), the future has decided that it is not ready, but it's possible that the polling thread is paused here and the worker thread was scheduled and finished its work.
The worker thread will then call the waker and request the future be polled again. If the waker decided to not poll the future again since it's polling the future right now, then the waker will never receive a wake up request again.
This means that the waker may discard wake up requests which come before
poll was called, but it's not allowed to discard wake up requests which
came during the future's poll call.
The only question I have: why would you like to reschedule polling for one more frame?
Since your actual work has to be done in a separate thread (not inside fn poll) then it doesn't make any sense to reschedule polling.

Related

why does Rc works in async fn

I found this example compile successfully, but isn't Rc<> thread unsafe? What if tikio start multi thread to execute test fn, won't it cause Rc to run on different threads?
use std::rc::Rc;
use tokio::join;
use std::time;
use async_std::task::{sleep};
async fn test(t:Rc<String>){
let k = t;
println!("1. test,{:?}", k);
sleep(time::Duration::from_secs(1)).await;
println!("2. test,{:?}", k);
}
#[tokio::main]
async fn main() {
let r = Rc::new("abc".to_string());
let f1 = test(r.clone());
let f2 = test(r.clone());
join!(f1,f2);
}
This is a bit nuanced, but #[tokio::main] will rewrite your async main() into something like this:
fn main() {
tokio::runtime::Builder::new_multi_thread()
.enable_all()
.build()
.unwrap()
.block_on(async {
// your code from `async main()`
})
}
The last step that actually runs everything, .block_on(), does not require the given task to be thread-safe (a.k.a. implement Send) because it will not be ran on a separate thread, even when using the multi-threaded executor:
This runs the given future on the current thread, blocking until it is complete, and yielding its resolved result.
Other tokio utilities and any spawned tasks may be ran on separate threads, and even move between them, but not the initial task.

What is the difference between "await callingMethodAsync()" and callingMethodAsync().wait()"? [duplicate]

I don't quite understand the difference between Task.Wait and await.
I have something similar to the following functions in a ASP.NET WebAPI service:
public class TestController : ApiController
{
public static async Task<string> Foo()
{
await Task.Delay(1).ConfigureAwait(false);
return "";
}
public async static Task<string> Bar()
{
return await Foo();
}
public async static Task<string> Ros()
{
return await Bar();
}
// GET api/test
public IEnumerable<string> Get()
{
Task.WaitAll(Enumerable.Range(0, 10).Select(x => Ros()).ToArray());
return new string[] { "value1", "value2" }; // This will never execute
}
}
Where Get will deadlock.
What could cause this? Why doesn't this cause a problem when I use a blocking wait rather than await Task.Delay?
Wait and await - while similar conceptually - are actually completely different.
Wait will synchronously block until the task completes. So the current thread is literally blocked waiting for the task to complete. As a general rule, you should use "async all the way down"; that is, don't block on async code. On my blog, I go into the details of how blocking in asynchronous code causes deadlock.
await will asynchronously wait until the task completes. This means the current method is "paused" (its state is captured) and the method returns an incomplete task to its caller. Later, when the await expression completes, the remainder of the method is scheduled as a continuation.
You also mentioned a "cooperative block", by which I assume you mean a task that you're Waiting on may execute on the waiting thread. There are situations where this can happen, but it's an optimization. There are many situations where it can't happen, like if the task is for another scheduler, or if it's already started or if it's a non-code task (such as in your code example: Wait cannot execute the Delay task inline because there's no code for it).
You may find my async / await intro helpful.
Based on what I read from different sources:
An await expression does not block the thread on which it is executing. Instead, it causes the compiler to sign up the rest of the async method as a continuation on the awaited task. Control then returns to the caller of the async method. When the task completes, it invokes its continuation, and execution of the async method resumes where it left off.
To wait for a single task to complete, you can call its Task.Wait method. A call to the Wait method blocks the calling thread until the single class instance has completed execution. The parameterless Wait() method is used to wait unconditionally until a task completes. The task simulates work by calling the Thread.Sleep method to sleep for two seconds.
This article is also a good read.
Some important facts were not given in other answers:
async/await is more complex at CIL level and thus costs memory and CPU time.
Any task can be canceled if the waiting time is unacceptable.
In the case of async/await we do not have a handler for such a task to cancel it or monitoring it.
Using Task is more flexible than async/await.
Any sync functionality can by wrapped by async.
public async Task<ActionResult> DoAsync(long id)
{
return await Task.Run(() => { return DoSync(id); } );
}
async/await generate many problems. We do not know if await statement will be reached without runtime and context debugging. If first await is not reached, everything is blocked. Sometimes even when await seems to be reached, still everything is blocked:
https://github.com/dotnet/runtime/issues/36063
I do not see why I must live with the code duplication for sync and async method or using hacks.
Conclusion: Creating Tasks manually and controlling them is much better. Handler to Task gives more control. We can monitor Tasks and manage them:
https://github.com/lsmolinski/MonitoredQueueBackgroundWorkItem
Sorry for my english.

How to run an async task daily in a Kestrel process?

How do I run an async task in a Kestrel process with a very long time interval (say daily or perhaps even longer)? The task needs to run in the memory space of the web server process to update some global variables that slowly go out of date.
Bad answers:
Trying to use an OS scheduler is a poor plan.
Calling await from a controller is not acceptable. The task is slow.
The delay is too long for Task.Delay() (about 16 hours or so and Task.Delay will throw).
HangFire, etc. make no sense here. It's an in-memory job that doesn't care about anything in the database. Also, we can't call the database without a user context (from a logged-in user hitting some controller) anyway.
System.Threading.Timer. It's reentrant.
Bonus:
The task is idempotent. Old runs are completely irrelevant.
It doesn't matter if a particular page render misses the change; the next one will get it soon enough.
As this is a Kestrel server we're not really worried about stopping the background task. It'll stop when the server process goes down anyway.
The task should run once immediately on startup. This should make coordination easier.
Some people are missing this. The method is async. If it wasn't async the problem wouldn't be difficult.
I am going to add an answer to this, because this is the only logical way to accomplish such a thing in ASP.NET Core: an IHostedService implementation.
This is a non-reentrant timer background service that implements IHostedService.
public sealed class MyTimedBackgroundService : IHostedService
{
private const int TimerInterval = 5000; // change this to 24*60*60 to fire off every 24 hours
private Timer _t;
public async Task StartAsync(CancellationToken cancellationToken)
{
// Requirement: "fire" timer method immediatly.
await OnTimerFiredAsync();
// set up a timer to be non-reentrant, fire in 5 seconds
_t = new Timer(async _ => await OnTimerFiredAsync(),
null, TimerInterval, Timeout.Infinite);
}
public Task StopAsync(CancellationToken cancellationToken)
{
_t?.Dispose();
return Task.CompletedTask;
}
private async Task OnTimerFiredAsync()
{
try
{
// do your work here
Debug.WriteLine($"{TimerInterval / 1000} second tick. Simulating heavy I/O bound work");
await Task.Delay(2000);
}
finally
{
// set timer to fire off again
_t?.Change(TimerInterval, Timeout.Infinite);
}
}
}
So, I know we discussed this in comments, but System.Threading.Timer callback method is considered a Event Handler. It is perfectly acceptable to use async void in this case since an exception escaping the method will be raised on a thread pool thread, just the same as if the method was synchronous. You probably should throw a catch in there anyway to log any exceptions.
You brought up timers not being safe at some interval boundary. I looked high and low for that information and could not find it. I have used timers on 24 hour intervals, 2 day intervals, 2 week intervals... I have never had them fail. I have a lot of them running in ASP.NET Core in production servers for years, too. We would have seen it happen by now.
OK, so you still don't trust System.Threading.Timer...
Let's say that, no... There is just no fricken way you are going to use a timer. OK, that's fine... Let's go another route. Let's move from IHostedService to BackgroundService (which is an implementation of IHostedService) and simply count down.
This will alleviate any fears of the timer boundary, and you don't have to worry about async void event handlers. This is also a non-reentrant for free.
public sealed class MyTimedBackgroundService : BackgroundService
{
private const long TimerIntervalSeconds = 5; // change this to 24*60 to fire off every 24 hours
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
// Requirement: "fire" timer method immediatly.
await OnTimerFiredAsync(stoppingToken);
var countdown = TimerIntervalSeconds;
while (!stoppingToken.IsCancellationRequested)
{
if (countdown-- <= 0)
{
try
{
await OnTimerFiredAsync(stoppingToken);
}
catch(Exception ex)
{
// TODO: log exception
}
finally
{
countdown = TimerIntervalSeconds;
}
}
await Task.Delay(1000, stoppingToken);
}
}
private async Task OnTimerFiredAsync(CancellationToken stoppingToken)
{
// do your work here
Debug.WriteLine($"{TimerIntervalSeconds} second tick. Simulating heavy I/O bound work");
await Task.Delay(2000);
}
}
A bonus side-effect is you can use long as your interval, allowing you more than 25 days for the event to fire as opposed to Timer which is capped at 25 days.
You would inject either of these as so:
services.AddHostedService<MyTimedBackgroundService>();

Difference between returning a Task and using async/await [duplicate]

Is there any scenario where writing method like this:
public async Task<SomeResult> DoSomethingAsync()
{
// Some synchronous code might or might not be here... //
return await DoAnotherThingAsync();
}
instead of this:
public Task<SomeResult> DoSomethingAsync()
{
// Some synchronous code might or might not be here... //
return DoAnotherThingAsync();
}
would make sense?
Why use return await construct when you can directly return Task<T> from the inner DoAnotherThingAsync() invocation?
I see code with return await in so many places, I think I might have missed something. But as far as I understand, not using async/await keywords in this case and directly returning the Task would be functionally equivalent. Why add additional overhead of additional await layer?
There is one sneaky case when return in normal method and return await in async method behave differently: when combined with using (or, more generally, any return await in a try block).
Consider these two versions of a method:
Task<SomeResult> DoSomethingAsync()
{
using (var foo = new Foo())
{
return foo.DoAnotherThingAsync();
}
}
async Task<SomeResult> DoSomethingAsync()
{
using (var foo = new Foo())
{
return await foo.DoAnotherThingAsync();
}
}
The first method will Dispose() the Foo object as soon as the DoAnotherThingAsync() method returns, which is likely long before it actually completes. This means the first version is probably buggy (because Foo is disposed too soon), while the second version will work fine.
If you don't need async (i.e., you can return the Task directly), then don't use async.
There are some situations where return await is useful, like if you have two asynchronous operations to do:
var intermediate = await FirstAsync();
return await SecondAwait(intermediate);
For more on async performance, see Stephen Toub's MSDN article and video on the topic.
Update: I've written a blog post that goes into much more detail.
The only reason you'd want to do it is if there is some other await in the earlier code, or if you're in some way manipulating the result before returning it. Another way in which that might be happening is through a try/catch that changes how exceptions are handled. If you aren't doing any of that then you're right, there's no reason to add the overhead of making the method async.
Another case you may need to await the result is this one:
async Task<IFoo> GetIFooAsync()
{
return await GetFooAsync();
}
async Task<Foo> GetFooAsync()
{
var foo = await CreateFooAsync();
await foo.InitializeAsync();
return foo;
}
In this case, GetIFooAsync() must await the result of GetFooAsync because the type of T is different between the two methods and Task<Foo> is not directly assignable to Task<IFoo>. But if you await the result, it just becomes Foo which is directly assignable to IFoo. Then the async method just repackages the result inside Task<IFoo> and away you go.
If you won't use return await you could ruin your stack trace while debugging or when it's printed in the logs on exceptions.
When you return the task, the method fulfilled its purpose and it's out of the call stack.
When you use return await you're leaving it in the call stack.
For example:
Call stack when using await:
A awaiting the task from B => B awaiting the task from C
Call stack when not using await:
A awaiting the task from C, which B has returned.
Making the otherwise simple "thunk" method async creates an async state machine in memory whereas the non-async one doesn't. While that can often point folks at using the non-async version because it's more efficient (which is true) it also means that in the event of a hang, you have no evidence that that method is involved in the "return/continuation stack" which sometimes makes it more difficult to understand the hang.
So yes, when perf isn't critical (and it usually isn't) I'll throw async on all these thunk methods so that I have the async state machine to help me diagnose hangs later, and also to help ensure that if those thunk methods ever evolve over time, they'll be sure to return faulted tasks instead of throw.
This also confuses me and I feel that the previous answers overlooked your actual question:
Why use return await construct when you can directly return Task from the inner DoAnotherThingAsync() invocation?
Well sometimes you actually want a Task<SomeType>, but most time you actually want an instance of SomeType, that is, the result from the task.
From your code:
async Task<SomeResult> DoSomethingAsync()
{
using (var foo = new Foo())
{
return await foo.DoAnotherThingAsync();
}
}
A person unfamiliar with the syntax (me, for example) might think that this method should return a Task<SomeResult>, but since it is marked with async, it means that its actual return type is SomeResult.
If you just use return foo.DoAnotherThingAsync(), you'd be returning a Task, which wouldn't compile. The correct way is to return the result of the task, so the return await.
Another reason for why you may want to return await: The await syntax lets you avoid hitting a mismatch between Task<T> and ValueTask<T> types. For example, the code below works even though SubTask method returns Task<T> but its caller returns ValueTask<T>.
async Task<T> SubTask()
{
...
}
async ValueTask<T> DoSomething()
{
await UnimportantTask();
return await SubTask();
}
If you skip await on the DoSomething() line, you'll get a compiler error CS0029:
Cannot implicitly convert type 'System.Threading.Tasks.Task<BlaBla>' to 'System.Threading.Tasks.ValueTask<BlaBla>'.
You'll get CS0030 too, if you try to explicitly typecast it.
This is .NET Framework, by the way. I can totally foresee a comment saying "that's fixed in .NET hypothetical_version", I haven't tested it. :)
Another problem with non-await method is sometimes you cannot implicitly cast the return type, especially with Task<IEnumerable<T>>:
async Task<List<string>> GetListAsync(string foo) => new();
// This method works
async Task<IEnumerable<string>> GetMyList() => await GetListAsync("myFoo");
// This won't work
Task<IEnumerable<string>> GetMyListNoAsync() => GetListAsync("myFoo");
The error:
Cannot implicitly convert type 'System.Threading.Tasks.Task<System.Collections.Generic.List>' to 'System.Threading.Tasks.Task<System.Collections.Generic.IEnumerable>'

async is snowballing to callers, can't make constructor async

I have a function loadData that loads some text from a file:
Future<String> loadAsset() async {
return await rootBundle.loadString('assets/data/entities.json');
}
The loadString method is from Flutter SDK, and is asynchronous.
The loadAsset method is then called in another method, that must me marked as async, since loadAsset is async and I need to use await:
Future<List<Entity>> loadEntities() async {
String jsonData = await loadAsset();
return parseData(jsonData);
}
The parseData method is not async, it receives a String, parse it, and return a list of objects:
List<Entity> parseData(String jsonString) {
...
}
But since loadEntities must be marked with async, this requires that it returns a Future, but in practice, it's not a Future because since I use await, it awaits for the loadAsset method to finish, then call the parseData funcion using the result.
This easily turns into a snowball of async call, because every method that uses loadEntities must be marked as async too.
Also, I can't use loadEntities in a class constructor, because the constructor should be marked as async, which is not allowed in Dart.
Am I using the async/await pattern in Dart wrong? How could I use the loadEntities method in a class constructor?
No, async is contagious and there is no way to go back from async to sync execution.
async/await is only syntactic sugar for methodThatReturnsFuture().then(...)
Marking a method with async is only to allow you to use await inside its body. Without async you would still need to return a Future for calling code to only execute after the result of loadAsset() becomes available.
You can use the Future returned from the async call directly. This would look something like this:
class HasAsync {
HasAsync() {
asyncFunction().then((val) {
print(val);
});
}
Future<int> asyncFunction() async {
int val = await otherFunction();
return val;
}
}
You just can't use await within the non-async function.
As you've tagged this with 'flutter', I'm going to guess this is within a flutter app. If that's the case look at the docs for FutureBuilder - it might help with what you're trying to do.
I know I may be too late for you to make any use of this answer but I am writing it anyways hoping someone will find it useful. So here is my two cents.
I had the same thought process as you did when I first tried to figure out what is asynchronous programming and how it can be used.
Since the question is regarding Flutter, I will use dart to explain this.
First, let's dive in to the the basic actually the purpose of using async await in asynchronous programming.
According to the flutter documentation, the purpose of async and await keywords is to declaratively mark a function as asynchronous and use it's results.
To define an async function, add async before the function body
The await keyword works only in async functions.
Therefore, whenever you try to get an output from a function marked as asynchronous it will have no option but to return a Future. Look at the following example for more clarification.
Firstly, you have a function which will do some calculations
Secondly, you have a simple function which gets data from an API by doing a simple http get request.
finally another function which will process some data and print some values.
void processInfo(){
calculateStuff();
Future<Map> decodedData = getDataFromInternet();
getDataProcessed(decodedData);
}
so in synchronous programming this would mean that all three functions will execute one after another. But let's say the second function getDataFromInternet() is called asynchronously. A simple implementation would be like below.
Future<Map> getDataFromInternet() async {
http.Response response = await http.get(this._apiPath);
Map decodedData;
if (response.statusCode != 200)
print("invalid response. cannot proceed!");
else {
decodedData = jsonDecode(response.body);
}
return decodedData;
}
So the above function is required to return a future. The question is why?
It's simple. In this case, it's because since we want to return something and by the time the return statement is executed and the data from the 'get request' may or may not be available at that moment.
Thus, the function returns a Future type result which and either be in complete state or incomplete state.
So how can we process this result? As a matter of fact this can be done in 3 ways.
1. Method One - Handle it as a promise
So once the getDataFromInternet() function returns a Future result in this example, you need the process that future result like how you'd handle a promise in javascript. Refer the code sample below.
void getDataProcessed(Future<Map> data) {
print('getting data from future map');
data.then((d) {
print(d);
});
}
2. Method Two - mark the parent function asynchronous (contagious way)
void processInfo() async{
calculateStuff();
//now you can simply await that result and process the result rather
//than handling a Future<Map> result in this case.
//Note: it is not required to use future variable because we are awaiting
//for result
Map decodedData = await getDataFromInternet();
getDataProcessed(decodedData);
}
so in this case the getDataProcessed() function will look something like this.
void getDataProcessed(Map data) {
//this will simply print the data object which is complete result which is by
//no way is a promise object
print(data);
}
3. Method Three - Use the results from the asynchronous method in a synchronous function (non-contagious way)
In this case the processInfo() function will change slightly, i.e. the getDataProcessed() will no longer be invoked in this method and will look something like this.
void processInfo(){
calculateStuff();
getDataFromInternet();
}
Instead of invoking getDataProcessed() in processInfo() function, we can use the result from getDataFromInternet() function to invoke the getDataProcessed() function.this mean we won't have to mark processInfo() as async and we can process getDataProcessed() method after we finish executing getDataFromInternet() method. The following code sample demonstrates how to do it.
void getDataFromInternet() async {
http.Response response = await http.get(this._apiPath);
Map decodedData;
if (response.statusCode != 200)
print("invalid response. cannot proceed!");
else {
decodedData = jsonDecode(response.body);
}
//in this case, since we are awaiting for get results response and the
//function is not expected to return anything the data type passed into
//getDataProcessed() function now will be of type Map rather than being type
//Future<Map> . Thus allowing it to be a synchronous function and without
//having to handle the future objects.
getDataProcessed(decodedData);
}
void getDataProcessed(Map data) {
//this will simply print the data object which is complete result which is by
//no way is a promise object
print(data);
}
So revising back this long answer,
async/await is just the declarative way to mark asynchronous functions
when an asynchronous function is called it can be handled in 3 ways.
get the return Future and handle it like a promise with the use of 'then()' function so no need to mark the parent
function async
mark the parent function async and handle the returned object with await to force the function to wait for the result.
call the desired function with the output of the async function at the end of the async function. This will allow the main
function to continue non-dependent functions while waiting for the
results of the async function and one the async function get the
results it can go in to the other function at the end and execute it
with the data received.
then and await are different. await will stop the program there until the Future task is finished. However then will not block the program. The block within then will be executed when the Future task is finished afterwards.
If you want your program to wait for the Future task, then use await. If you want your program to continue running and the Future task do it things "in the background", then use then.
As to your problem, I suggest redesign it. Do the loading assets and other async things that are needed for the constructor elsewhere. After these tasks are completed, then call the constructor.

Resources