`MessageChannel` too slow
Problem Description
MessageChannel seems too slow when you try to communicate between Workers.
When I try to send message from Worker to main thread (or vice versa) usually it takes 50-90 milliseconds even with high-end devices.
Doesn't matter what you try to send. One int value or shareable ByteArray or some big amount of data - result (delay) the same.
It makes Workers unusable for a lot of tasks like decoding MJPEG video stream in Worker and transfer decoded image to main thread for visualization.
Tested with multiple AIR versions, even with latest AIR 51.2.1.5 with multiple Windows/macOS devices with different architectures and applications. Tested with different data types and data amount. With and without ADL. The same issue in all cases.
Related issues: https://github.com/airsdk/Adobe-Runtime-Support/issues/3865 https://github.com/airsdk/Adobe-Runtime-Support/issues/3048 https://github.com/airsdk/Adobe-Runtime-Support/issues/2139#issuecomment-1463703743 https://github.com/airsdk/Adobe-Runtime-Support/issues/1773 https://github.com/airsdk/Adobe-Runtime-Support/issues/33 https://github.com/airsdk/Adobe-Runtime-Support/discussions/3078
Steps to Reproduce
Launch application with code below. It send 500 MB ByteArray from main thread to Worker 10 times and receive "confirmation" about receiving.
It will send 5 times shareable ByteArray and 5 times non-shareable ByteArray.
"Confirmation" here - it's just a int value with ByteArray length just to check that everything fine.
In traces you will see time elapsed from sending data from the main thread to "callback" ("confirmation") from Worker that data was received.
Application example with sources and Scout logs attached. messagechannel_delay.zip
package {
import flash.display.Sprite;
import flash.events.Event;
import flash.system.MessageChannel;
import flash.system.Worker;
import flash.system.WorkerDomain;
import flash.utils.ByteArray;
import flash.utils.getTimer;
public class MessageChannelDelay extends Sprite {
private var mainToWorkerBytes:MessageChannel;
private var workerToMain:MessageChannel;
private var worker:Worker;
private var beforeTime:int;
private var nextShareable:Boolean = false;
private var repeats:int = 10;
public function MessageChannelDelay() {
if (Worker.current.isPrimordial){
startMainThread();
} else {
startWorkerThread();
}
}
private function startMainThread():void {
worker = WorkerDomain.current.createWorker(loaderInfo.bytes, true);
mainToWorkerBytes = Worker.current.createMessageChannel(worker);
worker.setSharedProperty("mainToWorkerBytes", mainToWorkerBytes);
workerToMain = worker.createMessageChannel(Worker.current);
worker.setSharedProperty("workerToMain", workerToMain);
workerToMain.addEventListener(Event.CHANNEL_MESSAGE, onWorkerToMainBytes);
worker.start();
trace("Type", "Is shareble?", "Time", "Length");
sendBytes();
}
private function startWorkerThread():void {
mainToWorkerBytes = Worker.current.getSharedProperty("mainToWorkerBytes");
workerToMain = Worker.current.getSharedProperty("workerToMain");
mainToWorkerBytes.addEventListener(Event.CHANNEL_MESSAGE, onMainToWorkerBytes);
}
private function onMainToWorkerBytes(event:Event):void {
var bytes:ByteArray = mainToWorkerBytes.receive();
workerToMain.send(bytes.length);
bytes.clear();//Clear memory of shared ByteArray
}
private function sendBytes():void {
var bytes:ByteArray = new ByteArray();
bytes.shareable = nextShareable;
bytes.length = 500 * 1024 * 1024;
beforeTime = getTimer();
mainToWorkerBytes.send(bytes);
if (!nextShareable) bytes.clear();//Clear memory for local copy of ByteArray
}
private function onWorkerToMainBytes(event:Event):void {
var len:uint = workerToMain.receive();
var afterTime:int = getTimer();
trace("ByteArray", nextShareable ? 'Shareble' : 'Not shareble', (afterTime-beforeTime) + " ms", len / 1024 / 1024, 'MB');
nextShareable = !nextShareable;
if (--repeats > 0) sendBytes();
else trace("Done");
}
}
}
Actual Result:
In traces you will see a lot of time elapsed to transfer shareble ByteArray (or any other "light" data):
Type Is shareble? Time Length
ByteArray Not shareble 573 ms 500 MB
ByteArray Shareble 0 ms 500 MB
ByteArray Not shareble 634 ms 500 MB
ByteArray Shareble 55 ms 500 MB
ByteArray Not shareble 669 ms 500 MB
ByteArray Shareble 53 ms 500 MB
ByteArray Not shareble 634 ms 500 MB
ByteArray Shareble 89 ms 500 MB
ByteArray Not shareble 623 ms 500 MB
ByteArray Shareble 50 ms 500 MB
Done
Expected Result:
In traces you will see that transfering shareble ByteArray (or any other "light" data) takes ~0 milliseconds:
Type Is shareble? Time Length
ByteArray Not shareble 573 ms 500 MB
ByteArray Shareble 0 ms 500 MB
ByteArray Not shareble 634 ms 500 MB
ByteArray Shareble 0 ms 500 MB
ByteArray Not shareble 669 ms 500 MB
ByteArray Shareble 0 ms 500 MB
ByteArray Not shareble 634 ms 500 MB
ByteArray Shareble 0 ms 500 MB
ByteArray Not shareble 623 ms 500 MB
ByteArray Shareble 0 ms 500 MB
Done
Known Workarounds
none