不同的HTTP调用,等待相同的任务 [英] Different HTTP calls, await same Task

查看:79
本文介绍了不同的HTTP调用,等待相同的任务的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个 Task ,它启动获胜过程,如果尚未创建文件,则生成文件并返回.问题在于该动作被多次调用.更确切地说,它是< track> 元素的 src 属性.我有 ConcurrentDictionary< Guid,Task< string>> 跟踪当前正在运行哪个ID

I have a Task which starts a win process, which generates file if its not created yet and returns it. The problem is that the action is called more than once. To be more precisely its src attribute of a <track> element. I have ConcurrentDictionary<Guid, Task<string>> which keeps track of for which Id a process is currently running

public async Task<string> GenerateVTTFile(Guid Id)
{
  if (_currentGenerators.TryGetValue(id, out Task<string> task))
  {
     return await task; // problem is here?
  }

  var t = Run(); // Task
  _currentGenerators.TryAdd(id, t);

  return await t;
}

在控制器的动作方法中

var path = await _svc.GetSomePath();
if (string.IsNullOrEmpty(path))
{
    var path = await svc.GenerateVTTFile(id);

    return PhysicalFile(path, "text/vtt");
} 

return PhysicalFile(path, "text/vtt");

Run()方法只是启动 Process 并等待它.

Run() method is just starting Process and waits it.

process.WaitForExit();

我想要实现的是针对相同的ID返回相同任务的结果.看来,如果字典中已经存在 Id ,并且我 await ,它将启动另一个进程(再次调用Run方法).

What I want to achieve is to return the result of the same task for the same Id. It seems that if the Id already exists in the dictionary and I await it starts another process (calls Run method again).

有没有办法做到这一点?

Is there a way to achieve that?

推荐答案

您可以使方法变为原子性以保护危险区域":

You can make the method atomic to protect the "dangerzone":

private SemaphoreSlim _sem = new SemaphoreSlim(1);

public Task<string> GenerateVTTFile(Guid Id)
{
  _sem.Wait();
  try
  {
     if (_currentGenerators.TryGetValue(Id, out Task<string> task))
     {
        return task;
     }

     var t = Run(); // Task
     _currentGenerators.TryAdd(Id, t); // While Thread 1 is here,
                                       // Thread 2 can already be past the check above ...
                                       // unless we make the method atomic like here.

     return t;
   }
   finally
   {
      _sem.Release();
   }
}

这里的缺点是,具有不同 id的调用也必须等待.因此,这是一个瓶颈.当然,您可以做出努力,但是,嘿:.net团队帮您做到了:

Drawback here is, that also calls with different ids have to wait. So that makes for a bottleneck. Of course, you could make an effort but hey: the dotnet guys did it for you:

最好,您可以使用

Preferably, you can use GetOrAdd to do the same with only ConcurrentDictionary's methods:

public Task<string> GenerateVTTFile(Guid Id)
{
     // EDIT: This overload vv is actually NOT atomic!
     // DO NOT USE: 
     //return _currentGenerators.GetOrAdd(Id, () => Run());
     // Instead:
     return _currentGenerators.GetOrAdd(Id, 
                                        _ => new Lazy<Task<string>>(() => Run(id))).Value;
     // Fix "stolen" from Theodore Zoulias' Answer. Link to his answer below.
     // If you find this helped you, please upvote HIS answer.
}

是的,它确实是单线".请查看以下答案: https://stackoverflow.com/a/61372518/982149 我从中获取了修复程序错误的答案.

Yes, it's really a "one-liner". Please see this answer: https://stackoverflow.com/a/61372518/982149 from which I took the fix for my flawed answer.

这篇关于不同的HTTP调用,等待相同的任务的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆