异步读取图像文件
Posted
技术标签:
【中文标题】异步读取图像文件【英文标题】:Read an image file asynchronously 【发布时间】:2019-02-20 19:15:57 【问题描述】:我想,我尝试使用 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....
【问题讨论】:
您的代码甚至无法编译,因为您的 AddImage 方法应该是异步的 你的文件有多大? 请注意,async
方法始终在调用线程上运行,直到到达实际的 await
语句(实际上意味着它是 IO 绑定的)。另请注意,当此await
完成时,工作将返回到同一(调用)线程。从理论上讲,这可能是滞后的原因。
@touseefbsb 我知道 IDE 告诉我的。这是代码的副本。
@PoulBak 文件不是很大,但 CPU 很垃圾。尝试与 Hololens 合作
【参考方案1】:
您不需要 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 完成,简化了从另一个线程使用 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);
);
);
【讨论】:
以上是关于异步读取图像文件的主要内容,如果未能解决你的问题,请参考以下文章