【问题标题】:What is the best way to delay a console application for a few seconds将控制台应用程序延迟几秒钟的最佳方法是什么
【发布时间】:2012-02-22 13:23:21
【问题描述】:

概览。

我有一个用 C# .NET 4.0 编写的 Windows 服务,它连接到 Betfair API 以自动下注(所有下注决定都在 SQL DB 中完成)。该服务有许多计时器,可以为 3 个主要区域设置一些轮询(下注、检查价格、下注 [在比赛期间])。计时器都是每 30 秒触发一次。

我遇到困难的是 InPlay 投注。计时器每 30 秒调用一次 BetfairBot 对象中的一个方法,该方法会检查即将到来的有 inplay 投注的比赛。可能有多个系统投注同一场比赛,所以我想在并行中启动“控制”方法,这样一个系统就可以在下注之前等待另一个系统完成。

所以我有一些这样的代码来触发并行控制方法

// some SQL to get my upcoming races
DataTable sqlRecordset = this.dataAccess.GetDataTable(SQL);

try
{

// run in parallel for each system and concurrent races

Parallel.ForEach(sqlRecordset.AsEnumerable(), recordsetRow =>
{

    betfairLogon = recordsetRow["BetfairLogon"].ToString();
    betfairPassword = recordsetRow["BetfairPassword"].ToString();
    SystemPK = Convert.ToInt32(recordsetRow["SystemPK"]);
    systemName = recordsetRow["SystemName"].ToString();
    RacePK = Convert.ToInt32(recordsetRow["RaceFK"]);

    // spawn thread for each system    
    this.RunInPlayBettingControl(SystemPK, betfairLogon, betfairPassword, systemName, RacePK);

});


}
catch (Exception e)
{
// log error
HelperLib.LogMsg("Error starting Parallel Threads for RacePK: " + RacePK.ToString() + " - " +e.Message.ToString());
}

然后在我的控制方法中循环直到下注结束,调用另一个处理下注的方法并返回一个结果代码告诉我的系统下注的状态,例如比赛是否已经结束、尚未开始或即将开始开始。

对于其中几个状态,我想在重新调用投注方法之前延迟我的线程几秒钟。

我试过了

Thread.Sleep(2500);

但这根本不等待,投注过程会立即再次调用而无需等待。

我已经阅读了一些关于线程的信息,但我不知道问题是出在我的 Parallel 循环上,它触发了对我的控制方法的并行调用(它需要按需延迟线程)还是我的控制方法和Thread.Sleep(delay) 调用。

我在 Service 类中的初始计时器工作正常,我不知道解决这个问题的最佳方法或延迟的问题是什么,因为我假设 Parallel 循环启动的每个线程都将在其上运行拥有并因此在需要时通过 .Sleep 调用延迟。

我应该使用更多计时器还是其他方法,我现有的循环代码的最佳方法是什么?

由 Parallel 循环触发的 Control 方法如下。实际投注方法的代码过于复杂,无法在此处发布,但它没有线程调用,只有一些 SQL 和一些对 Betfair API 的调用。

任何帮助将不胜感激。提前致谢。

public void RunInPlayBettingControl(int SystemPK,string betfairLogon, string betfairPassword, string systemName, int RacePK)
{
int result = 0;
bool quit = false; // we loop until true

// decode our encrypted logon details
betfairPassword = HelperLib.GetPassword(betfairLogon);
betfairLogon = HelperLib.DecodeLogon(betfairLogon);

// create API object
this.betfairAPI = new BetfairAPI(systemName);

// try and log in for this system and save the session for future use

if (!String.IsNullOrEmpty(betfairLogon) && !String.IsNullOrEmpty(betfairPassword))
{

// check logged in status as we might have used previous session otherwise log in now
if (!this.betfairAPI.IsLoggedIn() && this.betfairAPI.Login(betfairLogon, betfairPassword) == false)
{
    // couldnt login so exit
    return;
}
else
{                  

    // save session to file
    this.betfairAPI.SaveSession(systemName);

    // we loop until we know there is no more point in doing so
    while (!quit)
    {
    // result code values
    // 0 = We have no idea whats going on yet
    // 1 = Race is actually closed/finished so exit
    // 2 = Race is inplay but we are not ready to bet yet - wait a short while
    // 3 = Race is inplay and ready to bet
    // 4 = Race is not inplay yet so wait a bit and carry on

    // this is our main betting method that handles all our betting
    result = this.RunInPlayBetting(SystemPK, betfairLogon, betfairPassword, systemName, RacePK);

    // check result to see if we quit looping
    switch (result)
    {
        case 1:
        // race is over so exit
        quit = true;
        break;
        case 2:
        // race is in play but not over our marker yet so go back in after a short wait
         Thread.Sleep(1000);  // NOT WORKING
        quit = false;

        break;
        case 3:
        // race is in play so lets go straight back in and try some more betting
        quit = false; 
        break;
        case 4:
        // not in play yet so keep looping after a short wait
        quit = false;

        Thread.Sleep(2500); // NOT WORKING

        break;

        case 0:
        // have no idea whats going just quit loop
        quit = true;
        break;

    }
    }
}

}   

return;
}

【问题讨论】:

  • 与其睡觉,不如设置一个计时器,以便在您想继续操作时调用。
  • 嗨,你怎么看它在我的 while 循环的上下文中工作。控制方法中的计时器,它在某些状态代码上递归调用自身,或者用新方法完全重写,如果是这样,你推荐什么方法?另外,为了我自己的理智,我想知道为什么并行循环产生的线程不能休眠?
  • 但它不起作用,因为这就是我目前正在做的事情。

标签: c# .net multithreading windows-services parallel-processing


【解决方案1】:

我不完全确定你在追求什么。您希望能够暂时停止对 RunInPlayBettingControl 方法的所有新调用吗?如果是,那么您必须进行线程同步。这样做:

class XYZ
{
  Object syncObj = new Object();
  ...

  public void RunInPlayBettingControl(int SystemPK,string betfairLogon, string betfairPassword, string systemName, int RacePK)
  {
    lock(this.syncObj)
    { }
    ...

    switch(...)
    {
      ...
      case 2:
      // race is in play but not over our marker yet so go back in after a short wait
      lock(this.syncObj)
      {
          Thread.Sleep(1000);
      }
      ...
    }
  }
}

这样您将保留对 RunInPlayBettingControl 的任何新调用,但正在运行的调用将完成。

这有帮助吗?

虽然您通常应该避免调用 Thread.Sleep,因为在此期间线程处于锁定等待状态,它会阻止应用程序退出(除非它是后台线程)。

【讨论】:

  • 没问题 - 希望你现在好多了。
【解决方案2】:

Thread.Sleep(2500);

但这根本不需要等待,并且会立即调用投注过程 无需等待。

Thread.Sleep() 将暂停 current 线程指定的时间。您看到的是执行相同方法的其他线程(我假设您在那里有一个断点用于检查),因为您使用Parallel.ForEach() 生成了一堆线程。

【讨论】:

  • 实时调试有点困难,当比赛正在进行时,但我已经这样做了,在大多数情况下,99% Parallel.ForEach 循环只有一个项目要循环(一场比赛,只有一个系统)因此只有一个线程从该循环中产生。所以没有其他调用同时产生线程。另外,在对使用 Parallel.ForEach 的方法的计时器调用之间有一个很好的时间间隔,如果代码已经在运行,我将放入一个标志以防止它运行尽管理想情况下它并不重要,或者我不想要它,因为它运行的次数越多,我下注的机会就越大
  • 那么我应该在控制方法或递归函数或其他方法中使用计时器和委托吗?
猜你喜欢
  • 2011-10-09
  • 2019-10-25
  • 1970-01-01
  • 2011-01-21
  • 1970-01-01
  • 1970-01-01
  • 2015-04-24
  • 2022-01-18
  • 1970-01-01
相关资源
最近更新 更多