我正在开发一个 C# 库,它使用 NVIDIA 的 CUDA 将某些工作任务卸载到 GPU。一个例子是使用扩展方法将两个数组相加:
float[] a = new float[]{ ... }
float[] b = new float[]{ ... }
float[] c = a.Add(b);
这段代码中的工作是在 GPU 上完成的。但是,我希望它异步完成,这样只有在需要结果时才会在 CPU 块上运行代码(如果结果尚未在 GPU 上完成)。为此,我创建了一个隐藏异步执行的 ExecutionResult 类。在使用中,它看起来如下:
float[] a = new float[]{ ... }
float[] b = new float[]{ ... }
ExecutionResult res = a.Add(b);
float[] c = res; //Implicit converter
在最后一行,如果数据已经准备好,程序会阻塞。我不确定在 ExecutionResult 类中实现这种阻塞行为的最佳方法,因为我对同步线程和这类事情不是很有经验。
public class ExecutionResult<T>
{
private T[] result;
private long computed = 0;
internal ExecutionResult(T[] a, T[] b, Action<T[], T[], Action<T[]>> f)
{
f(a, b, UpdateData); //Asych call - 'UpdateData' is the callback method
}
internal void UpdateData(T[] data)
{
if (Interlocked.Read(ref computed) == 0)
{
result = data;
Interlocked.Exchange(ref computed, 1);
}
}
public static implicit operator T[](ExecutionResult<T> r)
{
//This is obviously a stupid way to do it
while (Interlocked.Read(ref r.computed) == 0)
{
Thread.Sleep(1);
}
return result;
}
}
传递给构造函数的 Action 是在 GPU 上执行实际工作的异步方法。嵌套的 Action 是异步回调方法。
我主要关心的是如何最好/最优雅地处理转换器中完成的等待,以及是否有更合适的方法来解决整个问题。如果我需要详细说明或进一步解释,请发表评论。