简体   繁体   English

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

[英]What is the best way to delay a console application for a few seconds

Overview. 概述。

I have a Windows Service written in C# .NET 4.0 that is hooking into the Betfair API to place bets automatically (all betting decisions are done in the SQL DB). 我有一个用C#.NET 4.0编写的Windows服务,该服务与Betfair API挂钩,可以自动进行投注(所有投注决定均在SQL DB中完成)。 The service has a number of timers that sets up some polling for 3 main areas (place pending bets, check prices, place in play bets [during the race]). 该服务具有多个计时器,这些计时器为3个主要区域设置了一些轮询(下注待决,查看价格,在比赛中下注)。 The timers are all triggered every 30 seconds. 计时器全部每30秒触发一次。

The one I am having difficulty with is the InPlay betting one. 我遇到的困难是InPlay投注之一。 Once every 30 seconds the timer calls a method in my BetfairBot object that checks for upcoming races that have inplay bets for them. 计时器每30秒一次调用我的BetfairBot对象中的方法,该方法检查即将进行的比赛并为其下注。 There could be multiple systems betting on the same race so I wanted to fire off the "control" method in parrallel so one system isn't waiting for the other to finish before being able to place its bets. 在同一场比赛上可能有多个系统下注,因此我想在parrallel中启动“控制”方法,因此一个系统在下注之前不会等待另一个系统完成。

So I have some code like this to fire off the parallel control methods 所以我有一些像这样的代码来触发并行控制方法

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

Then in my control method I loop until the betting is over, calling another method which handles the betting and returns a result code telling my system the status of the betting eg whether the race has finished, not started yet, or just about to start. 然后,在我的控制方法中,我循环执行直到下注结束,然后调用另一个处理下注的方法,并返回结果代码,告知我的系统下注的状态,例如,比赛是否结束,尚未开始或即将开始。

On a couple of these statuses I want to delay my thread for a couple of seconds before re-calling the betting method. 在这些状态中,我想在重新调用下注方法之前将线程延迟几秒钟。

I have tried 我努力了

Thread.Sleep(2500);

But this doesn't wait at all and the betting proc is called instantly again without waiting. 但这根本就不等待,投注过程无需等待就立即被再次调用。

I have read up a bit about threading and I don't know whether the problem is with my Parallel loop that triggers parallel calls to my control method (which needs to delay the thread on demand) or with my control method and the Thread.Sleep(delay) call. 我已经阅读了一些有关线程的知识,但不知道问题出在我的并行循环中,该循环触发对我的控制方法的并行调用(需要按需延迟线程),还是我的控制方法和Thread.Sleep (延迟)通话。

My initial timers that are in the Service class work fine and I don't know the best way of going about this or what the problem is with the delaying as I presumed each Thread initiated by the Parallel loop would be running on its own and therefore delayed with a .Sleep call if required. 我位于Service类中的初始计时器运行良好,我不知道解决此问题的最佳方法,也不知道延迟存在什么问题,因为我认为由并行循环启动的每个线程都将独立运行,因此如果需要,延迟一个.Sleep调用。

Should I use more timers OR another method, and what is the best way with my existing loop code? 我应该使用更多的计时器还是其他方法?现有的循环代码最好的方法是什么?

The Control method fired by the Parallel loop is below. 并行循环触发的Control方法如下。 The code for the actual betting method is too complicated to post here but it has no thread calls just some SQL and some calls to the Betfair API. 实际投注方法的代码过于复杂,无法在此处发布,但是它没有线程调用,而只是一些SQL和一些对Betfair API的调用。

Any help would be much appreciated. 任何帮助将非常感激。 Thanks in advance. 提前致谢。

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;
}

Thread.Sleep(2500); Thread.sleep代码(2500);

But this doesn't wait at all and the betting proc is called instantly again without waiting. 但这根本就不等待,投注过程无需等待就立即被再次调用。

Thread.Sleep() will suspend the current thread for the specified time. Thread.Sleep()将在指定时间内挂起当前线程。 What you are seeing is other threads executing the same method (I assume you have a breakpoint there for checking), since you spawned a bunch of them with Parallel.ForEach() . 您看到的是其他线程执行相同的方法(我假设您那里有一个断点用于检查),因为您使用Parallel.ForEach()生成了一堆。

I am not totally sure what you're after. 我不太确定你要干什么。 Do you want to be able to temporarily stop all new calls to RunInPlayBettingControl method? 您是否希望能够暂时停止对RunInPlayBettingControl方法的所有新调用? If yes then you must do threads synchronization. 如果是,则必须执行线程同步。 Do it like that: 那样做:

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);
      }
      ...
    }
  }
}

This way you will hold any new calls to RunInPlayBettingControl but running ones will finish. 这样,您将保留对RunInPlayBettingControl的任何新调用,但运行中的调用将结束。

Is this any helpful? 这有帮助吗?

Generally though you should avoid calling Thread.Sleep because during that time thread is in lock wait state and it would prevent application from exiting (unless it is background thread). 通常,尽管您应避免调用Thread.Sleep,因为在此期间线程处于锁定等待状态,这将阻止应用程序退出(除非它是后台线程)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM