我想异步读取图像文件,而我正尝试使用C#中的async/await
来实现。但是,我仍然注意到此实现的重大滞后。使用剖析器,我非常有信心,FileStream.ReadAsync()
方法要花一些时间才能完成,而不是异步进行并阻止游戏更新。
我注意到,这种方式比仅使用File.ReadAllBytes
的方式更滞后,这很奇怪。我不能使用仍会导致一些滞后的方法,并且我希望不停止帧速率。
这是一些代码。
// Static class for reading the image.
class AsyncImageReader
{
public static async Task<byte[]> ReadImageAsync(string filePath)
{
byte[] imageBytes;
didFinishReading = false;
using (FileStream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read, 4096, true))
{
imageBytes = new byte[fileStream.Length];
await fileStream.ReadAsync(imageBytes, 0, (int) fileStream.Length);
}
didFinishReading = true;
return imageBytes;
}
}
// Calling function that is called by the OnCapturedPhotoToDisk event. When this is called the game stops updating completely rather than
public void AddImage(string filePath)
{
Task<byte[]> readImageTask = AsyncImageReader.ReadImageAsync(filePath);
byte [] imageBytes = await readImageTask;
// other things that use the bytes....
}
答案 0 :(得分:0)
您不需要Task来异步加载图像。您可以使用Unity的UnityWebRequest
和DownloadHandlerTexture
API进行加载。 UnityWebRequestTexture.GetTexture
简化了此过程,因为它会自动为您设置DownloadHandlerTexture
。这是在引擎盖下的另一个线程中完成的,但是您可以使用协程对其进行控制。
public RawImage image;
void Start()
{
StartCoroutine(LoadTexture());
}
IEnumerator LoadTexture()
{
string filePath = "";//.....
UnityWebRequest uwr = UnityWebRequestTexture.GetTexture(filePath);
yield return uwr.SendWebRequest();
if (uwr.isNetworkError || uwr.isHttpError)
{
Debug.Log(uwr.error);
}
else
{
Texture texture = ((DownloadHandlerTexture)uwr.downloadHandler).texture;
image.texture = texture;
}
}
您还可以使用Thread
API将文件加载到另一个线程中。更好的是,使用ThreadPool
API。他们中的任何一个都应该工作。加载图像字节数组后,要将字节数组加载到Texture2D
中,您必须在主线程中执行此操作,因为您无法在主线程中使用Unity的API。
要在完成加载图像字节后从另一个线程使用Unity的API,则需要使用包装器。下面的示例使用C#ThreadPool
和我的UnityThread
API完成,该API简化了从另一个线程使用Unity API的工作。您可以从这里抢UnityThread
。
public RawImage image;
void Awake()
{
//Enable Callback on the main Thread
UnityThread.initUnityThread();
}
void ReadImageAsync()
{
string filePath = "";//.....
//Use ThreadPool to avoid freezing
ThreadPool.QueueUserWorkItem(delegate
{
bool success = false;
byte[] imageBytes;
FileStream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read, 4096, true);
try
{
int length = (int)fileStream.Length;
imageBytes = new byte[length];
int count;
int sum = 0;
// read until Read method returns 0
while ((count = fileStream.Read(imageBytes, sum, length - sum)) > 0)
sum += count;
success = true;
}
finally
{
fileStream.Close();
}
//Create Texture2D from the imageBytes in the main Thread if file was read successfully
if (success)
{
UnityThread.executeInUpdate(() =>
{
Texture2D tex = new Texture2D(2, 2);
tex.LoadImage(imageBytes);
});
}
});
}