Hi there,

I’m working on a bot to do social games on the fedi, and using the mastodon-async crate for communicating with the ActivityPub server in question. At the moment I’m using tokio mt as a runtime, though I’m new at async so if you think I shouldn’t let me know.

The pattern I want to implement is the following:

  • At any given time, a user sends a “play” message to the bot.
  • If the player list is empty, the player is added to it awaiting someone else.
  • Otherwise, the bot checks if there are enough players on its list (who have previously sent a play message). For some games, enough is 1, since it’s a 2-player game, for some it’s 3 or more.
  • If there are enough players, play commences. list is cloned for that match, then emptied so other players can get in.

What I’m not very clear is how to keep this list to assure that sequence will be respected. I.a., if two play messages come reasonably quick together, I want one to be processed, then entered on the list, or get the match to start; then the other to get processed.

My current thoughts:

  • I could use a channel that receives the player accounts. When a new player is added, it performs the logic.
  • I could use a mutex with a list (or an option player value for the degenerate case of 2-player games).

Any thoughts on what the reasonable thing to do is here? I’m very new to async and while I realise there’s probably lots of ways to do this, they’re not all equally ergonomic and I want to avoid myself future pain.

  • kevincox
    link
    fedilink
    arrow-up
    2
    ·
    1 year ago

    The regular versions are blocking. If an item isn’t available they will put the current OS thread to sleep and wait for the channel or mutex.

    This sort of defeats the purpose of async which is to allow many logical threads but actually consumes a small number of OS threads.

    When you wait on an async channel or mutex instead of blocking the current thread it will yield to the current executor. This will allow the current OS thread to run other tasks to run in the meantime. Then when the channel has an item or the lock is unlocked the executor will then continue running the original future from where it left off.

    It’s worth noting that on most major desktop executors/async runtimes this won’t actually cause any problems. They will spawn a new OS thread to run other tasks if you block one. This will use a bit more memory and maybe a small latency blip but ultimately not be a major issue. However some runtimes will have a fixed number of backing OS threads and blocking them will result in higher latency or deadlocks. So in general you shouldn’t block in async functions.