并行性与异步C#

并行性与异步C#,c#,parallel-processing,C#,Parallel Processing,我正在用C#编写一个控制台应用程序,只要新的GPU可以免费使用,它就会接收一系列视频并对其进行转码。 应用程序将运行的计算机有两个GPU。但我真的有一段时间很难建立这个。 执行此作业的方法是FireTranscode() 它是由ManageTranscode()触发的 private async void managetracode() { 用于(计数器=0;计数器FireTranscode(计数器)); } } } 它假设调用FireTranscode,后跟参数计数器,40倍异步(视频变量的

我正在用C#编写一个控制台应用程序,只要新的GPU可以免费使用,它就会接收一系列视频并对其进行转码。 应用程序将运行的计算机有两个GPU。但我真的有一段时间很难建立这个。 执行此作业的方法是FireTranscode()

它是由ManageTranscode()触发的

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;
}