Advertisement
  1. This site uses cookies. By continuing to use this site, you are agreeing to our use of cookies. Learn More.

How AsyncTask reduces lag?

Comments in 'Plugin Development' started by RekkuzaRage, Dec 28, 2015.

  1. RekkuzaRage
    Offline

    RekkuzaRage Active Member

    Joined:
    Apr 15, 2014
    Posts:
    251
    Minecraft User:
    RekkuzaRage
    I have a basic understanding of AsyncTask, but don't understand how AsyncTask process code with less CPU usage. Can someone explain how it processes code and how it uses less CPU power?
  2. PEMapModder
    Offline

    PEMapModder Notable Member Plugin Developer

    Joined:
    Oct 9, 2013
    Posts:
    7,294
    Plugins:
    11
    Minecraft User:
    PEMapModder
    It does not use less CPU. It reduces the lag on the main thread, but it does not reduce CPU usage.
    [​IMG]
    This is apparently hilarious and unreasonable.
    AsyncTask is an object that has a function called onRun.

    PocketMine internally has some workers called "AsyncWorker"s. These async workers are executing on another thread. When you scheduleAsyncTask, PocketMine pushes your AsyncTask to a stack of AsyncTasks. When a worker has finished computing the previous AsyncTask, it will pull your AsyncTask from the AsyncPool and execute it. They are still executed on the same machine, possibly on another core (system-dependent, I guess), but definitely not giving you infinite CPU.
    So, it doesn't reduce CPU usage. Instead, it uses more CPU, but more efficiently instead of using the same old proportion of CPU used by PocketMine and making the server stuck.

    One fact you have to remember is that, AsyncTask is not a thread. You should only use it to run one-time stuff (e.g. usually takes less than one minute to execute). If you are using it to run repeating stuff, such as another server (e.g. an HTTP server like Volt or an IRC client like the IRCClient plugin), start a thread instead. Otherwise, you will keep one of the workers busy, and the server will get one less AsyncWorker although it should have it.

    We usually use async tasks for two situations:
    1. CPU-consuming code
      • No, this is not how you call setBlock() in a large loop in world edit. Remember that you cannot execute PocketMine core API stuff in AsyncTask or any other threads.
      • One example is when you want to, say, delete a very big directory (e.g. the .git/ directory of a Git repo with many commits and branches like PocketMine, or the world folder of a map with many generated chunks). That is not related to PocketMine core, but it is time-consuming to run ("lagging the server") (I would consider anything taking more than half a tick, i.e. 25 ms "lagging the server"). You wouldn't expect it to take too much time (like a whole hour) to run, and you may execute it quite frequently.
        • Disclaimer: my laptop spent 2 hours to delete all the cache files when I ran the pmt.mcpe.me web server on my laptop and forgot to add back the code to delete cache for a few months, and people keep trying to phar/unphar PocketMine releases on the website, sometimes even with the PHP binaries and/or the Git stuff
        • But this is irrelevant
      • For example, you may be copying/deleting a SkyWars map 5 times every 10 minutes). This is when you want to use AsycnTask. AsyncTask wouldn't magically use less CPU. But it executes in another thread, which is like in another process (or is it really in a subprocess/another process? I'm not sure about how pthreads works internally).
      • So instead of spending the server's core tick time to do stuff that you don't need to get done on the pulse, do it in another thread.
        • E.g. you can teleport the player to that world after the copying AsyncTask has completed; you don't need to do that immediately, and maybe your copying task spends 100 milliseconds to run, the player doesn't notice it but your server will lag behind for 2 ticks if you had not used an AsyncTask).
    2. Waiting-blocking
      • No, I didn't say waiting for a player to do something. You can simply use the event API or the scheduler API to do that instead of suspending an async worker.
      • This refers to thread-blocking function calls, such as curl_exec() (hence Utils::getURL(), Utils::postURL() and Utils::getIP(true)). HTTP requests (cURL execution) would lag your server, because it spends most of the time waiting for a response from another server.
        • Another example is MySQL queries. You aren't doing anything constructive in the majority time of a query function call. You are simply waiting for MySQL server to read your query, execute it and return a result.
      • Why spend all the main thread performance on waiting for a response?
      • It would of course be most convenient if you can set your queries/requests to be non-blocking and use a scheduler task to synchronously check if the server has respond. But in cases where you can't, we are simply putting the query aside and get a worker (another thread) stuck instead of getting the main thread stuck. Do you want the waiters look sick or the cooks to look sick, when your clients can see your waiters but not your cooks?
      • It doesn't save CPU. It just redistributes the CPU use.
    Last edited: Dec 28, 2015
  3. Legoboy0215
    Offline

    Legoboy0215 Notable Member

    Joined:
    Nov 1, 2014
    Posts:
    1,724
    Minecraft User:
    Legoboy0215
    Wait. Then how would you run stuff on the Async task if you can't do anything with PM?
  4. Gamecrafter
    Offline

    Gamecrafter

    Joined:
    Nov 20, 2014
    Posts:
    978
    Plugins:
    9
    Legoboy0215 likes this.
  5. Legoboy0215
    Offline

    Legoboy0215 Notable Member

    Joined:
    Nov 1, 2014
    Posts:
    1,724
    Minecraft User:
    Legoboy0215
    So you pass the Level object as a parameter, and execute stuff like setBlock(), the return it to main thread?
  6. Gamecrafter
    Offline

    Gamecrafter

    Joined:
    Nov 20, 2014
    Posts:
    978
    Plugins:
    9
    You should look at @Falk's MineReset code, it might help you grasp the concept.
  7. Legoboy0215
    Offline

    Legoboy0215 Notable Member

    Joined:
    Nov 1, 2014
    Posts:
    1,724
    Minecraft User:
    Legoboy0215
    Oh... So you need to unserialize first?
  8. PixelGuy75
    Offline

    PixelGuy75 Notable Member Plugin Developer

    Joined:
    Feb 9, 2014
    Posts:
    316
    Plugins:
    2
    Minecraft User:
    PixelGuy75
    Yes that is a good answer.
    Legoboy0215 likes this.
  9. PEMapModder
    Offline

    PEMapModder Notable Member Plugin Developer

    Joined:
    Oct 9, 2013
    Posts:
    7,294
    Plugins:
    11
    Minecraft User:
    PEMapModder
    Number one rule for threading - never pass any non-threaded objects to other threads thinking that they can be shared. They will be cloned instead of being shared.
    AsyncTask and threads are for doing things that are not related to PocketMine itself. You can do anything from and on external resources such as the filesystem and the internet, or your own simple variables (such as calculating a complicated string, or plotting a graph represented by a string using data from your plugin), but you must not interact with the core of PocketMine directly in threads.
  10. Legoboy0215
    Offline

    Legoboy0215 Notable Member

    Joined:
    Nov 1, 2014
    Posts:
    1,724
    Minecraft User:
    Legoboy0215
    I still don'tt understand. So this is why MineReset does not pass a Level as a parameter?
  11. PEMapModder
    Offline

    PEMapModder Notable Member Plugin Developer

    Joined:
    Oct 9, 2013
    Posts:
    7,294
    Plugins:
    11
    Minecraft User:
    PEMapModder
    No. It actually unloads the chunks and manages the chunks in the background and loads them later.
  12. PEMapModder
    Offline

    PEMapModder Notable Member Plugin Developer

    Joined:
    Oct 9, 2013
    Posts:
    7,294
    Plugins:
    11
    Minecraft User:
    PEMapModder
    Andrey Nazarchuk and Legoboy0215 like this.

Share This Page

Advertisement