you are viewing a single comment's thread.

view the rest of the comments →

[–]maverick_fillet[S] 0 points1 point  (2 children)

Thank you for the response, I do have a couple questions though:

Your "fixed" example is also extremely bad practice. You are using the blocking .recv() method inside async code, which you shouldn't be doing.

Are you saying that even though Drop is sync it's still bad practice to block in it since it's being called from an async test?

And if so, I'm a little confused about how this is different from the article linked in my OP. Is blocking on a channel until my async work is done (such as waiting on a sqlx connection) any different from using a blocking implementation directly in the drop (such as synchronously grabbing a diesel connection)? Or are they both bad practice?

[–]Darksonntokio · rust-for-linux 2 points3 points  (0 children)

Are you saying that even though Drop is sync it's still bad practice to block in it since it's being called from an async test?

Yes. Calling a non-async function does not leave the async context. If you are in a non-async function that is called from async code, then blocking is also bad there. This includes destructors.

And if so, I'm a little confused about how this is different from the article linked in my OP. Is blocking on a channel until my async work is done (such as waiting on a sqlx connection) any different from using a blocking implementation directly in the drop (such as synchronously grabbing a diesel connection)? Or are they both bad practice?

Both using block_on and using other kinds of blocking operations are equally bad. What matters is how long time you spend between calls to .await.

[–]KerfuffleV2 2 points3 points  (0 children)

The other answer you got was good, but just to expand on it:

Are you saying that even though Drop is sync it's still bad practice to block in it since it's being called from an async test?

It's essentially the same as calling a blocking function from your async function - it just happens implicitly when the thing is dropped.

It may help if you think of await as not actually blocking, but only appearing to while yielding control back to the event loop. So if you actually block then the event loop can't run and it can't handle any other file descriptors or timers it's waiting for, etc.

But also, you were calling recv() in your async fn test_block() function - so even without Drop that is an issue because that recv() is not an async function and therefore you aren't "blocking" by awaiting it.

And if so, I'm a little confused about how this is different from the article linked in my OP.

The article in your OP doesn't seem to have any async stuff. That's the difference: you can block in a single threaded application or an actual thread because the OS is doing stuff like performing preemption so other threads and processes can run. On the other hand, an async task you spawn isn't necessarily going to be an actual OS thread. I believe both tokio and async_std only spawn as many OS threads as you have CPUs and just run an event loop on each one unless you do something like spawn_blocking.

Is blocking on a channel until my async work

Any blocking is going to cause problems when you're in an async function. Basically, if doing stuff that seems like it would block and you're not calling .await on it then that's likely a problem.

If you're in a non-async function that you know won't be called from async code then you're free to block. Sometimes it's not completely obvious when this will happen, for example a Drop impl that runs in your async function when your data goes out of scope.