如何在异步环境中正确使用Fire&Forget

时间:2018-08-14 10:25:29

标签: c# asynchronous fire-and-forget

请考虑以下内容:

//base stuff
private readonly ConcurrentQueue<message> queue = new ConcurrentQueue<message>();
private readonly MyCacheData _cache  = new MyCacheData ();
//setuo
timer = new Timer { Interval = 60_000, AutoReset = true };
timer.Elapsed += OnTimedEvent;
httpClient.Timeout = new TimeSpan(0, 0, 60); // 60 seconds too
//

// each 60 seconds
private async void OnTimedEvent(object sender, ElapsedEventArgs e)
{
   if (cache 30 minutes old)
   { 
      //Fire and Forget GetWebDataAsync()
      // and continue executing next stuff
      // if I await it will wait 60 seconds worst case
      // until going to the queue and by this time another 
      // timed even fires
   }

   // this always should execute each 60 seconds
   if (queue isnt empty)
   {
       process queue
   }
}

// heavy cache update each 10-30 minutes
private async Task GetWebDataAsync()
{
   if (Semaphore.WaitAsync(1000))
   {
      try
      {
            //fetch WebData update cache
            //populate Queue if needed
      }
      catch (Exception)
      {
      }
      finally
      {
          release Semaphore
      }
   }
}

彩色:https://ghostbin.com/paste/6edov

因为我作弊并使用廉价的ConcurrentQueue解决方案,所以我不太在意GetWebDataAsync()期间发生的事情,所以我只想触发它并执行其工作,而我立即进入处理队列,因为它总是必须每60秒或计时器分辨率完成一次。

如何正确执行此操作,避免过多的开销或不必要的线程生成?

编辑:在其他地方为我的案件提供了答案

private async void OnTimedEvent(object sender, ElapsedEventArgs e)
{
    async void DoGetWebData() => await GetWebDataAsync()

    if (condition)
    { 
        DoGetWebData(); // Fire&Forget and continue, exceptions handled inside
    }

        //no (a)waiting for the GetWebDataAsync(), we already here
    if (queue isnt empty)
    {
        //process queue
    }

}


private async Task GetWebDataAsync()
{
    if (Semaphore.WaitAsync(1000))
    {
        try
        {
        //fetch WebData update cache
        //populate Queue if needed
        }
        catch (Exception)
        {
            //log stuff
        }
        finally
        {
            ///always release lock
        }
    }
}

2 个答案:

答案 0 :(得分:1)

Task.Run(...);
ThreadPool.QueueUserItem(...);

这些有什么问题吗?...

那又怎么样呢?

    ManualResetEvent mre = new ManualResetEvent(false);

    void Foo()
    {
        new Thread(() => 
        {
            while (mre.WaitOne())
            {
                /*process queue item*/
                if (/*queue is empty*/)
                {
                    mre.Reset();
                }
            }
        }) { IsBackground = true }.Start();
    }

    void AddItem()
    {
        /*queue add item*/
        mre.Set();
    }

答案 1 :(得分:0)

从另一个async方法中调用一个async方法没有 await语句

相关问题