Jump to content
Jarl

How do you handle async/threads?

Recommended Posts

I've been trying to do asynchronous tasks by using osbot's event and setting it as async, and using a runnable class to start a new thread. It seems to work well but I have some questions to ask.

 

  1. How do you pause other tasks or sleep the whole bot while on an async event/thread?
  2. Is there a proper way to do garbage collection for these async events/threads? (Seems like you can start/pause them but no proper way to "delete" them. I think this becomes a problem if you stop/start the script many times)
Link to post
Share on other sites

Hello Jarl

Im not an expert on threading at all. but This is how I did it in the past.

58 minutes ago, Jarl said:
  • How do you pause other tasks or sleep the whole bot while on an async event/thread?

 

Thread(){
  While(true){
    if (notpaused){
  	  do stoof
    }
	Sleep(random(500,1500))
  }
}
   @Override
    public void pause() {
       notpaused =false
    }
    @Override
    public void resume() {
       notpaused =true
    }

 

58 minutes ago, Jarl said:
  1. Is there a proper way to do garbage collection for these async events/threads? (Seems like you can start/pause them but no proper way to "delete" them. I think this becomes a problem if you stop/start the script many times)

Thread pools. 

https://www.geeksforgeeks.org/thread-pools-java/

https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ThreadPoolExecutor.html

 

 

 

 

 

  • Like 1
Link to post
Share on other sites

You will rarely need threads in scripts. I only use async events to correct API errors, e.g. force event termination for WebWalkEvent which used to take seconds to exit years ago. You should consider all possible approaches before resorting to threading. Threads may be justified as an abstraction of a specific task when you want to prioritize it, e.g. eating, which you decide to apply throughout the entire script and want to immediately stop whatever you were doing in order to eat.

 

Background task; execute for as long as the script is executing; do not stop while random solver is executing or when user pauses the script

Thread t = new Thread(() -> {
	while (getBot().getScriptExecutor().isRunning()) {
		// code
		try {
			Thread.sleep(69); 
		} catch (InterruptedException e) {
			break;
		}
	}
});
t.start();

 

Unknown iteration loop on script thread (do not use unless you can justify the need for this); stop when random solver kicks in or user presses pause/stop; the script executor conditions are added in order to make the pause/stop responsive in the case where the code you are executing catches the InterruptedException raised when they press those buttons; this shouldn't happen because that exception is not supposed to be caught, but adding these conditions prevents it from running forever (client buttons will not respond to clicks) if you want to be sure you don't get the client stuck and have to restart

while (condition 
       && getBot().getScriptExecutor().isRunning() 
       && !getBot().getScriptExecutor().isPaused() 
       && !getBot().getScriptExecutor().isSuspended()) {
	// ...
}

 

  • Like 1
Link to post
Share on other sites

@Nbacon@TokenThanks for your responses. I was actually thinking of doing a thread while webwalking or during combat. I understand both your threads would work, but from my experience, I had the main thread and the async thread competing with each other to control the mouse to do their thing. Eventually it works out, I was worried about the weird mouse interactions and something potentially not working. Another thing I was thinking of was potentially using a thread to handle other stuff like chat (good for async since it doesn't control the mouse?) and random events (which needs the mouse).

Is there a way to pause everything else instantly, when the thread "detects" something?

 

23 hours ago, Nbacon said:

Thanks for this. A good read, though not very useful for osbot since you would rarely need more than 1 thread. I found it useful elsewhere though.

20 hours ago, Token said:

Unknown iteration loop on script thread (do not use unless you can justify the need for this); stop when random solver kicks in or user presses pause/stop; the script executor conditions are added in order to make the pause/stop responsive in the case where the code you are executing catches the InterruptedException raised when they press those buttons; this shouldn't happen because that exception is not supposed to be caught, but adding these conditions prevents it from running forever (client buttons will not respond to clicks) if you want to be sure you don't get the client stuck and have to restart

Wouldn't this be similar to pausing the thread on exit/on pause/on resume?

Link to post
Share on other sites
2 hours ago, Nbacon said:

This is the thread that I asked for help with amost the same thing.

That's interesting! I guess we were both thinking of gracefully pausing webwalk to eat/high alch/whatever and then resuming the webwalk immediately after. My naive solution would have been to "sleep" the main thread and continue executing the async thread, but I couldn't find a solution for that.

2 hours ago, Nbacon said:

Ill look for the code and come back if i find it.

Thanks so much 😀

Link to post
Share on other sites

Here's a custom webwalk event class that I use to perform actions while walking without delays

import org.osbot.rs07.api.map.Position;
import org.osbot.rs07.event.WebWalkEvent;
import org.osbot.rs07.utility.ConditionalSleep2;

public class CustomWebWalk extends WebWalkEvent {

    private AsyncWalkEvent asyncWalkEvent;

    public CustomWebWalk(Position position) {
        super(position);
    }

    @Override
    public void onStart() {
        asyncWalkEvent = new AsyncWalkEvent();
        execute(asyncWalkEvent);
    }

    @Override
    public int execute() throws InterruptedException {
        if (asyncWalkEvent.isLooping()) {
            // Async is still looping, dont let the web walker execute
            return 600;
        }
        return super.execute();
    }

    @Override
    public void onEnd() throws InterruptedException {
        // End the async event and wait for it to finish
        asyncWalkEvent.setFinished();
        ConditionalSleep2.sleep(5000, asyncWalkEvent::hasCompleted);
    }

}

And the action that executes in a separate thread

import org.osbot.rs07.api.map.Position;
import org.osbot.rs07.event.Event;

public class AsyncWalkEvent extends Event {

    private volatile boolean finished = false;

    private volatile boolean isLooping = false;

    public AsyncWalkEvent() {
        setAsync();
    }

    @Override
    public int execute() throws InterruptedException {
        if (canPerformAction()) {
            // Map destination is far enough away, we can perform some actions
            isLooping = true;
            if (shouldDoAction()) {
                // do action
            } else {
                // any other necessary action
            }
            isLooping = false;
        }
        return 600;
    }

    @Override
    public void onEnd() throws InterruptedException {
        finished = true;
    }

    public boolean isLooping() {
        return isLooping;
    }

    public boolean hasCompleted() {
        return finished;
    }

    private boolean canPerformAction() {
        // Only allow the actions to start if the map destination is far enough away
        Position dest = getMap().getDestination();
        if (dest == null) return false;
        int dist = getMap().distance(dest);
        return dist < 20 && dist > 7;
    }

}

 

  • Like 2
Link to post
Share on other sites

 

interface ISOMETHING{
    void onStart();
    void execute();
    void onEnd();
    int time();
    boolean testAsBoolean();
}
public class d {

    boolean walkwalk(MethodProvider mp,int run, PathPreferenceProfile profile,boolean camera, Area area, ISOMETHING something) {

        WebWalkEvent walkEvent = new WebWalkEvent(area);
        walkEvent.setPathPreferenceProfile(profile);
        walkEvent.setEnergyThreshold(run);
        walkEvent.setMoveCameraDuringWalking(camera);
        Event event = new Event() {
            public void onStart() throws InterruptedException {
                this.setAsync();
                something.onStart();
            }
            public int execute() throws InterruptedException {

                if ( something.testAsBoolean()){
                    this.setBlocking();//impotant
                    something.execute();
                    this.setAsync();//impotant
                }
                return something.time();
            }
            public void onEnd() throws InterruptedException {
                something.onEnd();
            }
        };
        mp.execute(event);
        boolean done =   mp.execute(walkEvent).hasFinished();
        event.setFinished();
        return done;
    }
}

 

  • Like 1
Link to post
Share on other sites

@Camaro @NbaconThanks for your code snippets! Both are interesting approaches and I will put both to the test to see how it really interacts.

 

Sadly, it looks like you cannot do something asynchronously throughout a script, unless you prepare extensively for it which might be too much work.

Edited by Jarl
  • Heart 1
Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


  • Recently Browsing   0 members

    No registered users viewing this page.

×
×
  • Create New...