简体   繁体   English

并行和异步 C#

[英]Parallelism and Async C#

I'm writing a Console Application in C# that takes an array of videos and transcode it as long a new GPU is free to use.我正在 C# 中编写一个控制台应用程序,它需要一组视频并对其进行转码,只要新的 GPU 可以免费使用。 The machine where the app will run has two GPUs.运行应用程序的机器有两个 GPU。 But I'm really having a hard time how to build this up.但我真的很难建立这个。 The method that does the job is FireTranscode()完成这项工作的方法是FireTranscode()

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

and it's triggered by ManageTranscode()它由 ManageTranscode() 触发

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

It suppose to call the FireTranscode followed by the parameter counter, 40 times async (value of videos variable), and in case both GPU ( static Dictionary<int, bool> GPU = new Dictionary<int, bool> { { 0, true }, { 1, true } }; are in use (=false) it should wait until any task finishes and free for use (=true).它假设调用 FireTranscode 后跟参数计数器,异步 40 次(视频变量的值),如果 GPU ( static Dictionary<int, bool> GPU = new Dictionary<int, bool> { { 0, true }, { 1, true } };正在使用中 (=false) 它应该等到任何任务完成并免费使用 (=true)。

I'm trying to learn how to use it correctly and I would appreciate some tips and help how to achieve this.我正在尝试学习如何正确使用它,我将不胜感激一些提示并帮助实现这一目标。 Thank you.谢谢你。

You can simplify your logic and also make it more extensible in terms of available GPU by using below code.您可以使用以下代码简化逻辑,并使其在可用 GPU 方面更具可扩展性。 It uses SemaphoreSlim (also mentioned by @Poul Bak) which allows degree of parallelism by defined parameters.它使用SemaphoreSlim (@Poul Bak 也提到过),它允许通过定义的参数实现并行度。

Also, I've refactored your code to have GPU as class (you can use Struct too).另外,我已经重构了您的代码,使 GPU 为 class(您也可以使用 Struct)。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM