1. The forums will be archived and moved to a read only mode in about 2 weeks (mid march).

Creating Async Task and call methods from API

Discussion in 'Development' started by Bluplayz, Feb 15, 2017.

  1. Bluplayz

    Bluplayz Spider Jockey

    Messages:
    43
    GitHub:
    bluplayz
    How can i create an Async Task and call some functions from the API?

    I tried to make a new \Thread but then he dont known the API from Pocketmine xD

    any ideas?
     
  2. robske_110 (Tim)

    robske_110 (Tim) Wither Skeleton Poggit Reviewer

    Messages:
    1,342
    GitHub:
    robske110
    -_-
    When will people start to learn that threads are threads. Please use the search bar, i think i've already explained it somewhere.
     
    Last edited by a moderator: Feb 15, 2017
    jasonwynn10 likes this.
  3. Bluplayz

    Bluplayz Spider Jockey

    Messages:
    43
    GitHub:
    bluplayz
    i know but i search so often but doesnt find what i want :/
     
    Last edited by a moderator: Feb 15, 2017
  4. robske_110 (Tim)

    robske_110 (Tim) Wither Skeleton Poggit Reviewer

    Messages:
    1,342
    GitHub:
    robske110
    Short answer: You can't
     
  5. Bluplayz

    Bluplayz Spider Jockey

    Messages:
    43
    GitHub:
    bluplayz
    and what can i make to improve the performance for this:

    i have a mysql class and a task which save data from this server to mysql db and get the data of all other servers from the db, works fine but it need to read and save every second but i think that this will cause a lot of laggs in the same thread.. what can i do then?
     
  6. Bluplayz

    Bluplayz Spider Jockey

    Messages:
    43
    GitHub:
    bluplayz
    i use this for transfer my own packets to other servers which are not on the same root/vserver, i try something with sockets but doesnt find a good tutorial which helps me out about creating a socket connection to my servers and "sending a string" to the other server
     
  7. robske_110 (Tim)

    robske_110 (Tim) Wither Skeleton Poggit Reviewer

    Messages:
    1,342
    GitHub:
    robske110
    well, you can actually do mysql in a thread. just pass the data you want to send to the thread and then send it from there.
     
  8. Bluplayz

    Bluplayz Spider Jockey

    Messages:
    43
    GitHub:
    bluplayz
    what do you mean with 'pass' ?
     
  9. Muqsit

    Muqsit Chicken

    Messages:
    1,548
    GitHub:
    muqsit
    Short answer: You can
    PHP:
    public function onCompletion(Server $server)
    {
        
    //API function here.
    }
    ...just that it won't be done asynchronously. The only function that executes task asynchronously in an AsyncTask is the onRun() function. To port a function from the API to the AsyncTask, you need to convert the object or function to php-identifiables....or string (can be done with: serialize/json_decode/toString() API functions) in the constructor and assign it a global variable.

    Then you must reconstruct the string(ed) function/object in the onRun()

    Eg: Vector3 to async.
    PHP:
    private $vector3;

    public function 
    __construct(Vector3 $vec)
    {
        
    $this->vector3 = [$vec->x$vec->y$vec->z];
    }

    public function 
    onRun()
    {
        
    $vector3 = new Vector3($this->vector3[0], $this->vector3[1], $this->vector3[2]);
    }
     
    Last edited: Feb 15, 2017
    jasonwynn10 and Bluplayz like this.
  10. corytortoise

    corytortoise Skeleton

    Messages:
    825
    GitHub:
    corytortoise
    I think it is important to point out that while it is possible, it is not recommended, at least according to this.
     
    jasonwynn10 and Muqsit like this.
  11. SOFe

    SOFe Administrator Staff Member PMMP Team Poggit Admin

    Messages:
    1,968
    GitHub:
    sof3
    Short answer is too short. The rest is conceptually wrong.

    You can't call API methods on a separate thread. This is the undeniable fact; this is by definition of "API methods of PocketMine" and "threads". The main body (onRun) of an AsyncTask is run entirely on a worker thread, and it is incorrect, if not impossible to call API methods from AsyncTask::onRun().

    You may request a delayed call of API methods on the main thread from an AsyncTask using publishProgress() + onProgressUpdate(), or using onCompletion(), but you still cannot call API methods in other threads, but just in the main thread. You can pass serializable data between threads, and you can request the main thread to do something upon an object on the main thread through a complicated series of scheduling, but you cannot do them directly. You may break down objects and reconstruct them in another thread, but they will not be the same object, i.e. if you somehow pass the Player object to an AsyncTask (which is actually impossible because it has a Server reference), it will be a clone, and API methods won't work as they usually do.

    In other threads you may, however, call static API methods, such as Utils::getURL(), or even construct classes in the PocketMine API; but this is very dangerous, because if you aren't 100% sure what you are doing, you will end up trying to modify some data ineffectively without errors. PHP builtin functions are not API methods, but they are safe to use as long as they don't reference any storage in the main thread. For example, fopen() returns a resource, which is actually an integer pointing to a handle stored in the PHP process; this resource ID will mean something probably entirely different if passed to another thread. You can still use resources in other threads, but make sure you don't try to reference resources in the main thread.

    Therefore, trying to call an API method on other threads will fail silently. It is not possible, because you aren't calling API methods from the server at all; you are calling them probably on a clone of the server, or a clone of other objects, etc., which do not affect anything on the main thread.

    In response to @Bluplayz's scenario:
    Schedule a repeating task (which runs on the main thread) that fires an AsyncTask to run your MySQL operations every second. Prepare any input data you need in the main thread and simplify them into scalar or Threaded data (in this case, a query string may be appropriate, and probably the parameters to pass to mysqli_stmt::bind_param() too) (arrays can be passed as Volatile), store them appropriately and pass them to the AsyncTask subclass you make, which will execute the query in the onRun() method according to the input. For anything you want to do on the main thread after getting MySQL response, implement it in onCompletion(); if your onCompletion() implementation depends on any input from the main thread (e.g. if the MySQL query is due to a command, and you want to pass the CommandSender involved), use the parent AsyncTask::__construct(), which will store the data to a local storage and can be fetched using new additions in API 2.1.0.
    Note that mysqli_result and mysqli are in fact resources too, so make sure you convert them to scalar by serializing the fetched results -- mysqli_result::fetch_array() still involves the Internet; don't try to pass them directly!

    I have written a library called libasynql: https://github.com/poggit/libasynql It is in the Virion format, which is not fully completed yet; but you can read the source code just for reference.

    P.S. Citing @dktapps (a reliable reference at all? :D): threads are like roads, so the preposition before it should be "on", not "in".
    P.P.S. I really thought that this post is worth a thread in Resources ;) Considering a "Featured threads" section in plugin development forum.
     
  12. Bluplayz

    Bluplayz Spider Jockey

    Messages:
    43
    GitHub:
    bluplayz
    Thank you very much for the big "tutorial" :) you helped me a lot! now i try to make MySQL update and maybe Query on Async Task :)
     
  13. SOFe

    SOFe Administrator Staff Member PMMP Team Poggit Admin

    Messages:
    1,968
    GitHub:
    sof3
    Best practice is that you always do anything network-related in other threads. It would even be good to handle all MySQL queries in the same thread, or start your own async worker just for your connections if you have a lot of them.
     
    StuntzCo likes this.
  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.