我遇到了AS3编码AIR for android的工作者之间的通信速度问题。我的测试设备是Galaxy S2(android 4.0.4),我正在使用AIR18.0在flashdevelop中开发。
首先要做的事情。 我尝试通过共享对象进行良好的旧AMF序列化复制。我在物理引擎(辅助线程)上获得平均49次计算/秒,在主线程上具有稳定的60FPS。不得不把它调到超过300个动态物体上,以获得明显的减速。
一切顺利,所以我开始进行设备上的测试,那就是当狗屎开始侧身时。我的速度不到1.5步/秒。开始深入挖掘,编写了一些代码,以检查地狱的速度是如此之慢,我发现看共享对象有点像看着其他人看油漆干。
此时我开始深入研究。我发现有很多人已经在抱怨消息频道的速度(在共享对象上找不到太多,“开发人员”的现状我猜)。所以我决定使用共享的bytearrays和互斥量。 (我跳过了条件,因为我并不特别希望我的任何线程暂停)。
启动桌面调试器我得到了115-ish计算/ s和超过350次计算/ s直接回调(调试器确实抛出异常,不是为那种连续处理而设计的我猜...任何人。 )。共享的bytearray和互斥量就像宣传的那样,比我前女友的高潮更快。
我在S2上进行调试,看,我得到3.4次计算/秒,200个动态对象。
所以..手机上的并发性已经为我做了很多。然后我想我做了一点测试,没有任何沟通。相同的场景,物理进行超过可接受的40次计算/ s和图形运行在预期的60FPS ......
所以,我直截了当的问题是:
这是我的Com代码:
package CCom
{
import Box2D.Dynamics.b2Body;
import Box2D.Dynamics.b2World;
import flash.concurrent.Condition;
import flash.concurrent.Mutex;
import flash.utils.ByteArray;
import Grx.DickbutImage;
import Phx.PhxMain;
/**
* shared and executed across all threads.
* provides access to mutex and binary data.
*
* @author szeredai akos
*/
public class CComCore
{
//===============================================================================================//
public static var positionData:ByteArray = new ByteArray();
public static var positionMutex:Mutex = new Mutex();
public static var creationData:ByteArray = new ByteArray();
public static var creationMutex:Mutex = new Mutex();
public static var debugData:ByteArray = new ByteArray();
public static var debugMutex:Mutex = new Mutex();
//===============================================================================================//
public function CComCore()
{
positionData.shareable = true;
creationData.shareable = true;
debugData.shareable = true;
}
//===============================================================================================//
public static function encodePositions(w:b2World):void
{
var ud:Object;
positionMutex.lock();
positionData.position = 0;
for (var b:b2Body = w.GetBodyList(); b; b = b.GetNext())
{
ud = b.GetUserData();
if (ud && ud.serial)
{
positionMutex.lock();
positionData.writeInt(ud.serial); // serial
positionData.writeBoolean(b.IsAwake); // active state
positionData.writeInt(b.GetType()) // 0-static 1-kinematic 2-dynamic
positionData.writeDouble(b.GetPosition().x / PhxMain.SCALE); // x
positionData.writeDouble(b.GetPosition().y / PhxMain.SCALE); // y
positionData.writeDouble(b.GetAngle()); // r in radians
}
}
positionData.length = positionData.position;
positionMutex.unlock();
}
//===============================================================================================//
public static function decodeToAry(ar:Vector.<DickbutImage>):void
{
var index:int;
var rot:Number = 0;
positionData.position = 0;
while (positionData.bytesAvailable > 0)
{
//positionMutex.lock();
index = positionData.readInt();
positionData.readBoolean();
positionData.readInt();
ar[index].x -= (ar[index].x - positionData.readDouble()) / 10;
ar[index].y -= (ar[index].y - positionData.readDouble()) / 10;
ar[index].rotation = positionData.readDouble();
//positionMutex.unlock();
}
}
//===============================================================================================//
}
}
(忽略位置y上的低通滤波器 - =(y-x)/ c)
如此。 请注意,仅在解析物理时使用互斥锁确实会使性能提高约20%,同时对主线程的帧速率影响最小。这使我相信问题并不在于每个数据的写入和读取数据,而在于数据可用于第二个线程的速度。我的意思是,那些是字节数组运算,它很快就很自然。我确实通过简单地将远程线程转移到主线来检查速度,速度仍然是合理的。地狱,......即使在S2上也可以接受而不会抛弃额外的计算。
ps:我也尝试过发布版本。
如果没有人有可行的解决方案(除了.2-.4s缓冲区,以及明显的单线程),我确实希望听到有关wanky变通办法或至少是问题的具体来源。
事先提前答案 0 :(得分:1)
认为我发现了这个问题。 一如既往,事情比最初想的要复杂得多。
计时器事件以及设置间隔和超时都限制为60fps。只要应用程序在该特定点处空闲,或者在可以自由执行并且延迟已经过去之后立即执行,计时器就会按时执行。但显然,延迟不能短于15-ish(我认为它在台式机上更少)。应该不是问题吧?
然而
如果那段代码操纵共享对象,那么计时器会突然决定自己动手并在15毫秒内查看它,无论它是否有空闲时间。
无论如何,事情是共享对象,工作人员,计时器事件和adobe强加的60FPS限制之间存在错误的交互。
解决方法非常简单。让定时器在5000ms的大量延迟上,并在定时器事件的回调中做5000个循环。显然,下一个计时器事件在5000循环完成之前不会触发,但最重要的是它也不会添加那个巨大的延迟。
另一个奇怪的事情是5000循环期间互斥体的贪婪所有权所以必须使用flash.concurrent.Condition。
好处是性能提升并且令人印象深刻。
缺点是整个物理事物现在与主线程的帧速率(或主游戏循环所包含的任何装置)密切相关,但是嘿。我想,60Fps足够好了。
Zi MuleTrex-感兴趣的人的条件:
package CCom
{
import Box2D.Dynamics.b2Body;
import Box2D.Dynamics.b2World;
import flash.concurrent.Condition;
import flash.concurrent.Mutex;
import flash.utils.ByteArray;
import Grx.DickbutImage;
import Phx.PhxMain;
/**
* shared and executed across all threads.
* provides access to mutex and binary data.
*
* @author szeredai akos
*/
public class CComCore
{
//===============================================================================================//
public static var positionData:ByteArray = new ByteArray();
public static var positionMutex:Mutex = new Mutex();
public static var positionCondition:Condition = new Condition(positionMutex);
public static var creationData:ByteArray = new ByteArray();
public static var creationMutex:Mutex = new Mutex();
public static var debugData:ByteArray = new ByteArray();
public static var debugMutex:Mutex = new Mutex();
//===============================================================================================//
public function CComCore()
{
positionData.shareable = true;
creationData.shareable = true;
debugData.shareable = true;
}
//===============================================================================================//
public static function encodePositions(w:b2World):void
{
var ud:Object;
positionData.position = 0;
positionMutex.lock();
for (var b:b2Body = w.GetBodyList(); b; b = b.GetNext())
{
ud = b.GetUserData();
if (ud && ud.serial)
{
positionData.writeBoolean(b.IsAwake); // active state
positionData.writeInt(ud.serial); // serial
positionData.writeInt(b.GetType()) // 0-static 1-kinematic 2-dynamic
positionData.writeDouble(b.GetPosition().x / PhxMain.SCALE); // x
positionData.writeDouble(b.GetPosition().y / PhxMain.SCALE); // y
positionData.writeDouble(b.GetAngle()); // r in radians
}
}
positionData.writeBoolean(false);
positionCondition.wait();
}
//===============================================================================================//
public static function decodeToAry(ar:Vector.<DickbutImage>):void
{
var index:int;
var rot:Number = 0;
positionMutex.lock();
positionData.position = 0;
while (positionData.bytesAvailable > 0 && positionData.readBoolean())
{
//positionMutex.lock();
index = positionData.readInt();
positionData.readInt();
ar[index].x = positionData.readDouble();
ar[index].y = positionData.readDouble();
ar[index].rotation = positionData.readDouble();
//positionMutex.unlock();
}
positionCondition.notify();
positionMutex.unlock();
}
//===============================================================================================//
}
}
随着更多频道和byteArrays开始弹出,同步将变得更加复杂。