几秒钟延迟控制台应用程序的最佳方法是什么

时间:2012-01-30 18:52:02

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

概述。

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

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

所以我有一些像这样的代码来启动并行控制方法

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

但是这并没有等待,而是在没有等待的情况下立即再次调用投注过程。

我已经阅读了一些关于线程的内容,我不知道问题是我的并行循环触发并行调用我的控制方法(需要按需延迟线程)还是我的控制方法和Thread.Sleep(延迟)调用。

我在Service类中的初始定时器工作正常,我不知道解决这个问题的最佳方法或延迟问题是什么,因为我假设并行循环启动的每个Thread都将在其上运行拥有,因此如果需要,可以通过.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;
}

2 个答案:

答案 0 :(得分:3)

  

Thread.sleep代码(2500);

     

但是这并不等待,并立即调用投注过程   再也没有等待。

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

答案 1 :(得分: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,因为在那段时间线程处于锁定等待状态,这会阻止应用程序退出(除非它是后台线程)。