并行性与异步C#
我正在用C#编写一个控制台应用程序,只要新的GPU可以免费使用,它就会接收一系列视频并对其进行转码。 应用程序将运行的计算机有两个GPU。但我真的有一段时间很难建立这个。 执行此作业的方法是FireTranscode() 它是由ManageTranscode()触发的并行性与异步C#,c#,parallel-processing,C#,Parallel Processing,我正在用C#编写一个控制台应用程序,只要新的GPU可以免费使用,它就会接收一系列视频并对其进行转码。 应用程序将运行的计算机有两个GPU。但我真的有一段时间很难建立这个。 执行此作业的方法是FireTranscode() 它是由ManageTranscode()触发的 private async void managetracode() { 用于(计数器=0;计数器FireTranscode(计数器)); } } } 它假设调用FireTranscode,后跟参数计数器,40倍异步(视频变量的
private async void managetracode()
{
用于(计数器=0;计数器<视频;计数器++)
{
如果(GPU[0]==false&GPU[1]==false)
{
等待任务。WhenAny(代码转换列表);
}
其他的
{
transcodeList.Add(Task.Factory.StartNew(()=>FireTranscode(计数器));
}
}
}
它假设调用FireTranscode,后跟参数计数器,40倍异步(视频变量的值),如果GPU(static Dictionary GPU=new Dictionary{{0,true},{1,true};
正在使用(=false),它应该等待任何任务完成并可以自由使用(=true)
我正在努力学习如何正确使用它,我希望能得到一些提示并帮助实现这一点。
谢谢。您可以使用下面的代码简化您的逻辑,并使其在可用GPU方面更具可扩展性。它使用
信号量LIM
(也由@Poul Bak提及),允许通过定义的参数实现并行度
此外,我还重构了您的代码,使GPU成为类(您也可以使用Struct)
private object lockObj=new object();
private List availableGPUs=List(){/*在此处初始化GPU*/};
private int AvailableGPUCount{get{return availableGPUs.Count();}
专用异步void ManageTrancode()
{
int maxThread=AvailableGPUCount;
SemaphoreSlim lockSlim=新的信号量lim(maxThread,maxThread);
用于(int counter=0;counterg.IsAvailable);
gpu.IsAvailable=false;
}
返回gpu;
}
专用无效释放GPU(int gpuId)
{
锁(lockObj)
{
availableGPUs.First(g=>g.Id==gpuId).IsAvailable=true;
}
}
专用级GPU
{
公共int Id{get;set;}
public bool IsAvailable{get;set;}=true;
}
Lookup'SemaphoreSlim'-这可以限制您的代码一次只能运行2个。提示:首先if(GPU[0]==false&GPU[1]==false)
看起来很奇怪,请执行if(!GPU[0]&&&!GPU[1])
,并了解&
和&
之间的区别。对于GPU=PickGPU(0)也一样==true?0:1
使其成为gpu=PickGPU(0)?0:1
。错误:Task.Factory.StartNew()
不是等待的,用Task.Run()
代替。注意Thread.Sleep(rand.Next(1,5))
睡眠时间从1毫秒到5毫秒,可以吗?@aepot很好的提示!1,5的情况下,我删除了3个零进行连接,但在发布之前忘了将它们放回。也不知道奇怪的代码,你的方法是一个更好的练习,谢谢你的提示,现在有很多东西要学习谢谢你练习这些评论ove,这就完成了我需要更多了解的主题!
private void FireTranscode(int counter)
{
Random rand = new Random();
int gpu;
lock (thisLock)
{
gpu = PickGPU(0) == true ? 0 : 1;
GPU[gpu] = false;
if (gpu == 0) { gpuZero += 1; } else { gpuOne += 1; };
Thread.Sleep(rand.Next(1, 5));
videos -= 1;
}
Console.WriteLine($"Transconding on {gpu} using thread: {Thread.CurrentThread.ManagedThreadId} {transcodeArray[Convert.ToInt32(counter), 2]}");
GPU[gpu] = true;
}
private async void ManageTrancode()
{
for(counter=0; counter < videos; counter++)
{
if (GPU[0] == false & GPU[1] == false)
{
await Task.WhenAny(transcodeList);
}
else
{
transcodeList.Add(Task.Factory.StartNew(() => FireTranscode(counter)));
}
}
}
private object lockObj = new object();
private List<GPU> availableGPUs = List<GPU>() { /* initialize GPUs here */};
private int AvailableGPUCount { get { return availableGPUs.Count(); } }
private async void ManageTrancode()
{
int maxThread = AvailableGPUCount;
SemaphoreSlim lockSlim = new SemaphoreSlim(maxThread, maxThread);
for(int counter = 0; counter < videos; counter++)
{
await lockSlim.WaitAsync();
await Trancode();
lockSlim.Release();
}
}
private async Task Trancode()
{
GPU gpu = GetAndLockGPU();
// await <<Run actual trancode here>>
ReleaseGPU(gup.Id);
}
private GPU GetAndLockGPU()
{
GPU gpu = null;
lock (lockObj)
{
gpu = availableGPUs.First(g => g.IsAvailable);
gpu.IsAvailable = false;
}
return gpu;
}
private void ReleaseGPU(int gpuId)
{
lock (lockObj)
{
availableGPUs.First(g => g.Id == gpuId).IsAvailable = true;
}
}
private class GPU
{
public int Id {get; set;}
public bool IsAvailable {get; set;} = true;
}