简体   繁体   English

使用Thread.Sleep限制每秒API调用次数?

[英]Restrict number of API calls per second with Thread.Sleep?

As always, im quite the noob, as im sure you will see from both my code and question. 与往常一样,我是菜鸟,相信您将从我的代码和问题中都看到。 For practice im currently writing an Xamarin.Android app for a game called Eve Online. 为了练习,我目前正在为名为Eve Online的游戏编写Xamarin.Android应用。 People there mine resources from planets to make cash. 那里的人从行星上开采资源来赚钱。 These mines have to be reset at different intervals, and the real pros can have up to 30 characters doing it. 这些地雷必须在不同的时间间隔进行重置,而真正的职业玩家最多可以使用30个角色来进行重置。 Each character can have 5 planets, usually there are at least 2 mines (extractors) on each. 每个角色可以有5个星球,通常每个星球上至少有2个地雷(提取器)。 So there could be 300 timers going on. 因此,可能有300个计时器在运行。

In my app you save your characters in an sqlite db, and every hour a intentservice runs through the API and checks your times and if their expired or not. 在我的应用程序中,您将角色保存在sqlite db中,并且每小时都有一个intentservice通过API运行并检查您的时间以及它们是否过期。 This is how i do that: 这就是我的方法:

public async Task PullPlanets(long KeyID, long CharacterID, string VCode, string CharName)
    {
        XmlReader lesern = XmlReader.Create("https://api.eveonline.com/char/PlanetaryColonies.xml.aspx?keyID=" + KeyID + "&vCode=" + VCode + "&characterID=" + CharacterID);

        while (lesern.Read())
        {
            long planet = 0;
            string planetName;
            planet = Convert.ToInt64(lesern.GetAttribute("planetID"));
            planetName = lesern.GetAttribute("planetName");

            if ((planet != 0) && (planetName != null))
            {
                planets.Add(planet);
                planetNames.Add(planetName);
                await GetExpirationTimes(CharName, planet, planetName, KeyID, CharacterID, VCode);

            }
        }

        lesern.Close ();
    }



    public async Task GetExpirationTimes(string CharName, long planetID, string planetName, long KeyID, long CharacterID, string VCode)
    {
        string planet = planetID.ToString();
        XmlReader lesern = XmlReader.Create("https://api.eveonline.com/char/PlanetaryPins.xml.aspx?keyID=" + KeyID + "&vCode=" + VCode + "&characterID=" + CharacterID + "&planetID=" + planet);


        while (lesern.Read())
        {
            string expTime;
            expTime = lesern.GetAttribute("expiryTime");

            if ((expTime != null) && (expTime != "0001-01-01 00:00:00"))
            {

                    allInfo.Add (new AllInfo (CharName, planetName, Convert.ToDateTime (expTime)));

            }
        }

        lesern.Close ();

        SendOrderedBroadcast (stocksIntent, null);
    }

}

After this, it sends the times back to my Activity, where they get added to an extractor. 在此之后,它将时间发送回我的活动,然后将它们添加到提取程序中。 It seems to work pretty fine, although ive only been able to test with 2 characters with a total of 14 extractors so far. 到目前为止,尽管我只能用2个字符进行测试,但总共14个提取程序,它似乎工作得很好。 An alarmmanger in activity calls the service every hour, and it sends a notification. 活动中的警报器每小时都会调用该服务,并发送通知。 When user opens the activity, it pulls the list from service, sorts it, and displays it. 当用户打开活动时,它将从服务中提取列表,对其进行排序并显示出来。 I would welcome input on if this is the way to do it. 如果这样做是可以接受的,我将表示欢迎。

I do see a problem in the horizon, though. 不过,我确实看到了一个问题。 The Eve API blocks if an app surpases 30 API-calls per second. 如果某个应用每秒超过30个API调用,则Eve API会阻塞。 Im pretty sure someone with 30 characters would do that. 我很确定有30个字符的人会做到这一点。 So, im wondering if i should add something to delay each call if a certain number is passed? 所以,我想知道如果通过某个号码,我是否应该添加一些东西来延迟每个呼叫? This is how i call the first XML call. 这就是我所说的第一个XML调用。

var table = db.Table<CharsList> ();

    foreach (var e in table) {

        long KeyIDOut = Convert.ToInt64(e.KeyID);
        long CharIDOut = Convert.ToInt64(e.CharacterID);
        string VCodeOut = e.VCode.ToString();
        string navnOut = e.Name.ToString();


            PullPlanets(KeyIDOut, CharIDOut, VCodeOut, navnOut);

        }

        CheckTimes ();

    }

Is it viable to add a 添加一个是否可行

 if (table.Count > 10) {

 foreach (var e in table) {
 //start the first characters call
 Thread.Sleep(100)

} }

The service is intentservice and not on UI thread. 该服务是intentservice,不在UI线程上。 I guess this would bring the calls under 30 a sec, but i have never used Thread.Sleep and fear what else could happen in my code. 我想这会使通话速度降低到30秒钟以下,但是我从未使用过Thread.Sleep,并且担心代码中还会发生什么。 Are there other things that could help me not blow the limit? 还有其他事情可以帮助我达到极限吗? Can this code handle 300 extractors? 该代码可以处理300个提取器吗?

I believe you are generally right in your approach. 我相信您通常是正确的。 I had to do a similar thing for a reddit client I was writing, except their limits is once a second or so. 我必须为正在编写的reddit客户做类似的事情,除了他们的限制大约是每秒一次。

The only problem I see with your setup is that assume that Thread.Sleep does sleep for the amount of time you give it. 我在安装程序中看到的唯一问题是,假设Thread.Sleep确实在给它的时间内睡眠。 Spurious wakeups are possible in some cases, so what I would suggest is that you give it a smaller value, save the last time you accessed the service and then put a loop around the sleep call that terminates once enough time has passed. 在某些情况下,可能会发生虚假唤醒,所以我建议您给它一个较小的值,保存上次访问该服务的时间,然后围绕睡眠调用循环,一旦经过足够的时间便终止。

Finally if you are going to be firing up a lot of intent services for a relatively short amount of work, you might want to have a normal service with a thread to handle the work - that way it will only have to be created once but it is still of the UI thread. 最后,如果您打算为相对较少的工作量提供大量的意图服务,则您可能希望有一个带有线程来处理工作的普通服务-这样,它只需创建一次即可,但是仍然是UI线程。

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

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