Author Topic: Calling functions asynchronously  (Read 2150 times)

I haven't used tork for a while and I have a general question.
 
Can I call functions asynchronously, or is tork completely synchronous. Is there a loophole that allows you call functions asynchronously?

/discuss

If by "asynchronously" you mean on a different thread, then no, all torquescript is done on a single thread.

You can however use schedules to call a function at a given time.

schedule(delay in ms, 0, functionname, a, r, g, u, m, e, n, t, s);

Yeah torquescript has no multi threading, which is what you need to do this properly. There's two workarounds and they're both stuffty in their own ways.

Expanding on ipquarx answer, you can use use schedules to create a scheduled looping function that calls a callback when completed:

function doWork()
{
    doSomeWork();
    If(workcomplete)
        handleWorkComplete();
     else
        schedule (10,0,dowork);
}

But even a few ms per tick can make this method take a hell of a long time if it has a lot of iterations to run through, and its only usable with workloads then can be split up iteratively/recursively. It will also still cause lag is each iteration is intensive


Another way is to offload the work to an external desktop application/web service by communicating through TCP/HTTP (which torque can do asynchronously), but obviously an add-on using the former would be unreleasable, whereas the latter would take longer to communicate and require you to host a reliable web server. Either way would only work with jobs taking simple inputs and returning simple outputs; that is, you wouldn't be able to read/modify the game world beyond the function's arguments and return value
« Last Edit: May 27, 2015, 12:37:40 PM by Headcrab Zombie »

Because HTTP / TCP requests are done in a separate thread (completely asynchronously) is it possible to sneak code into the request thread that is not directly related to the request?

There is no torquescript (at all) being run on a different thread, the only thing that's ran on a different thread is the TCP listener within the game engine itself.

Because HTTP / TCP requests are done in a separate thread (completely asynchronously) is it possible to sneak code into the request thread that is not directly related to the request?
Can we take a step back for a second and ask what you're trying to accomplish here?

Asynchrony is not the same thing as multithreading. In fact, they're almost entirely different things. An example of asynchrony is that you don't have to wait for a file to be read entirely before performing other operations. Torque is not asynchronous because functions block until they return, there is no way to allow the game to work on other things while a function is processing. However, you can write your functions in a way that emulates asynchrony. For example, if you were loading bricks, if you loaded them all at once (synchronously) without allowing the game to process, you'd block the thread and the game would lag. However, if you make a slight change to how you write the code, you can emulate asynchrony by telling the function to wait until the next frame (after everything else has been processed) to continue. The general form of this follows:

Synchronous:
Code: [Select]
function synchronousLoop() {
    for(%i = 0; %i < 500; %i++) {

        expensiveCalculation(%i);

    }
}

"Asynchronous":
Code: [Select]
function asynchronousLoop(%i) {

    expensiveCalculation(%i);

    if(%i++ < 500)
        schedule(0, 0, asynchronousLoop, %i);
}

Both functions are called the same way: synchronousLoop(); and asynchronousLoop(); and both will perform expensiveCalculation(%i) where %i is all values from 0 to 499. The difference is that the "asynchronous" function will allow game processing while it runs. There are two undesired side effects of this: the first is that the function will take significantly more time to process. The second is that you cannot return a value through the traditional (return %x;) way. The second is an obvious and accepted side effect of asynchrony, this is why we use callbacks. However, the first can become an issue, and it is possible to speed it up if necessary.

Code: [Select]
function asynchronousLooentrepreneur roved(%i) {

    for(%x = 0; %x < 5 && %i++ < 500; %x++) { // do 5 iterations at a time, but do not exceed 500 as a maximum.
        expensiveFunction(%i);
    }

    if(%i < 500)
        schedule(0, 0, asynchronousLooentrepreneur roved, %i);
    else
        asynchronousDoneCallback();
}

This example performs 5 iterations per frame. That means that the function will be done in 1/5 the frames, which should approximately equal 1/5 the time, excluding if you overrun the allocated frame size buffer and cause the game to lag. The name of this game is keeping the function low enough so it doesn't eat too much processing time and run into the next frame, but not so low that the function takes forever to preform. Keep in mind processing time varies based on a lot of factors and what may seem the perfect number in single player where any higher makes the game lag may not be the perfect number on a full multiplayer server running mods.

Asynchrony is not the same thing as multithreading. In fact, they're almost entirely different things.
Yeah but asynchrony oftentimes utilizes multithreading, so they do go hand in hand
« Last Edit: May 29, 2015, 08:28:28 AM by Headcrab Zombie »

Can we take a step back for a second and ask what you're trying to accomplish here?
I agree with Jetz. I think what the OP is asking is if you can preform multiple functions with one input, although I don't know about calling them asynchronously, since trinick is correct here:
telling the function to wait until the next frame (after everything else has been processed) to continue

For instance you can do

Code: [Select]
serverCMDDisplayMessage(%client)
{
     functionA();
     functionB();
}
Of course, functionA(); is called before functionB();
You could always call functionB(); inside of functionA(); but the process remains the same, funtionA(); is always checked before functionB(); unless otherwise stated

-snip-
I don't think he was asking that at all. He was pretty clear on the asynchronous part.

Goth, the whole point of this discussion is that if you have an expensive calculation as functionA(), functionB() would get processed before functionA() finishes. It's a rule of thumb that any post Goth makes you can expect to be completely missing the point..

Goth, the whole point of this discussion is that if you have an expensive calculation as functionA(), functionB() would get processed before functionA() finishes. It's a rule of thumb that any post Goth makes you can expect to be completely missing the point..
You could always call functionB(); inside of functionA(); but the process remains the same, funtionA(); is always checked before functionB(); unless otherwise stated
It's a rule of thumb that any post I make, Dannu reads improperly. );

Function B could easily be processed before Function A finishes, just nest it, or go with trinicks example and use a loop to call back and check the function
Also, TGE utilizes the event queue whereas TGEA does a better job at handling multitasking and asychronous callbacks.

Here I found an example documentation that uses asynchronous streams
https://github.com/GarageGames/Torque3D-FPSTutorial/blob/master/Engine/source/platform/async/asyncPacketStream.h
« Last Edit: May 30, 2015, 12:46:00 PM by Goth77 »

Function B could easily be processed before Function A finishes, just nest it, or go with trinicks example and use a loop to call back and check the function
This has nothing to do with what OP is asking or though

Here I found an example documentation that uses asynchronous streams
https://github.com/GarageGames/Torque3D-FPSTutorial/blob/master/Engine/source/platform/async/asyncPacketStream.h
That doesn't have anything to do with anything in this topic

This has nothing to do with what OP is asking or though
That doesn't have anything to do with anything in this topic
It's just an example -.-

I haven't used tork for a while and I have a general question.
Can I call functions asynchronously?
He's not asking for over complicated explanations, it's a general question
"can he call functions asynchronously"
the answer is yes

Yeah but asynchrony oftentimes utilizes multithreading, so they do go hand in hand

I think what you're thinking of is parallel processing. Parallel processing oftentimes utilizes multithreading because multithreading allows multiple things to be processed at once. Synchrony in computing means sequential processing, i.e. A then B then C is processed as A then B then C. Asynchrony means that things don't have to be processed sequentially, i.e. A then B then C can be processed as B then C then A. Usually the reason asynchrony is used is because functions will block until they are done, and this is undesirable. For example, a command to retrieve the next line from the command prompt will wait until the command has been input until continuing on to the next sequential command. This can be extremely undesired in the case of a game like Blockland where the game needs to process outside of every time someone inputs a command. I believe the way Torque solves this problem actually uses parallel processing and not asynchrony, because I believe it handles console input on a different parallel thread and still allows the thread to block, it just doesn't run anything else in that thread. However, the asynchronous way to deal with this would be to read from the stream and collect new letters into a buffer whenever the collection value from the stream mutates, and processing upon \n.

That's all irrelevant to the OP though.

Can I call functions asynchronously, or is tork completely synchronous.
the answer is yes

The answer is no. However...

Is there a loophole that allows you call functions asynchronously?
Yes! You can write functions to utilize schedule( time, refobj, function, args, ... ) to defer future processing until a future point in time. This stops thread blocking, which means the function will not run synchronously! It is, however, a work-around, because each iteration will run synchronously, but the function as a whole will not be synchronous.