c#有更好的等待模式吗?

pro*_*ach 78 c# multithreading design-patterns

我发现自己几次编写这种类型的东西.

for (int i = 0; i < 10; i++)
{
   if (Thing.WaitingFor())
   {
      break;
   }
   Thread.Sleep(sleep_time);
}
if(!Thing.WaitingFor())
{
   throw new ItDidntHappenException();
}
Run Code Online (Sandbox Code Playgroud)

它只是看起来像坏代码,有没有更好的方法这样做/它是一个糟糕的设计的症状?

Jar*_*Par 98

实现此模式的更好方法是让Thing对象公开消费者可以等待的事件.例如a ManualResetEventAutoResetEvent.这大大简化了您的消费者代码,如下所示

if (!Thing.ManualResetEvent.WaitOne(sleep_time)) {
  throw new ItDidntHappen();
}

// It happened
Run Code Online (Sandbox Code Playgroud)

Thing旁边的代码也没有那么复杂.

public sealed class Thing {
  public readonly ManualResetEvent ManualResetEvent = new ManualResetEvent(false);

  private void TheAction() {
    ...
    // Done.  Signal the listeners
    ManualResetEvent.Set();
  }
}
Run Code Online (Sandbox Code Playgroud)


Chr*_*isF 29

使用事件.

等待事件完成后(或在指定的时间内未能完成)然后在主应用程序中处理事件.

这样你就没有任何Sleep循环了.


Kei*_*thS 12

如果程序在等待时没有其他任何东西可以做(例如在连接到数据库时),则循环不是等待某些东西的可怕方式.但是,我发现你的一些问题.

    //It's not apparent why you wait exactly 10 times for this thing to happen
    for (int i = 0; i < 10; i++)
    {
        //A method, to me, indicates significant code behind the scenes.
        //Could this be a property instead, or maybe a shared reference?
        if (Thing.WaitingFor()) 
        {
            break;
        }
        //Sleeping wastes time; the operation could finish halfway through your sleep. 
        //Unless you need the program to pause for exactly a certain time, consider
        //Thread.Yield().
        //Also, adjusting the timeout requires considering how many times you'll loop.
        Thread.Sleep(sleep_time);
    }
    if(!Thing.WaitingFor())
    {
        throw new ItDidntHappenException();
    }
Run Code Online (Sandbox Code Playgroud)

简而言之,上面的代码看起来更像是一个"重试循环",它被认为更像是超时工作.以下是构建超时循环的方法:

var complete = false;
var startTime = DateTime.Now;
var timeout = new TimeSpan(0,0,30); //a thirty-second timeout.

//We'll loop as many times as we have to; how we exit this loop is dependent only
//on whether it finished within 30 seconds or not.
while(!complete && DateTime.Now < startTime.Add(timeout))
{
   //A property indicating status; properties should be simpler in function than methods.
   //this one could even be a field.
   if(Thing.WereWaitingOnIsComplete)
   {
      complete = true;
      break;
   }

   //Signals the OS to suspend this thread and run any others that require CPU time.
   //the OS controls when we return, which will likely be far sooner than your Sleep().
   Thread.Yield();
}
//Reduce dependence on Thing using our local.
if(!complete) throw new TimeoutException();
Run Code Online (Sandbox Code Playgroud)

  • -1:我的天啊!让我们通过像疯了一样把它循环来烧掉那个CPU!看,在编写在CLR上运行的代码时,你应该尝试更高层次的思考.这不是装配,你不编码PIC! (2认同)

Ste*_*ary 9

如果可能,将异步处理包装在一个Task<T>.这提供了所有世界中最好的:

  • 您可以使用任务延续以类似事件的方式响应完成.
  • 您可以等待使用完成的可等待句柄,因为Task<T>实现IAsyncResult.
  • 任务很容易使用Async CTP; 他们也很好玩Rx.
  • 任务有一个非常干净的内置异常处理系统(特别是,它们正确地保留了堆栈跟踪).

如果需要使用超时,则Rx或Async CTP可以提供.


SwD*_*n81 5

我会看看WaitHandle类。特别是等待对象设置的ManualResetEvent类。您还可以为其指定超时值并检查它是否在之后设置。

// Member variable
ManualResetEvent manual = new ManualResetEvent(false); // Not set

// Where you want to wait.
manual.WaitOne(); // Wait for manual.Set() to be called to continue here
if(!manual.WaitOne(0)) // Check if set
{
   throw new ItDidntHappenException();
}
Run Code Online (Sandbox Code Playgroud)