我已经阅读并查看了很多关于Threadpooling的示例,但我似乎无法理解它我需要的方式。我设法得到的工作并不是我真正需要的。它只是在自己的线程中运行该函数。
public static void Main()
{
while (true)
{
try
{
ThreadPool.QueueUserWorkItem(new WaitCallback(Process));
Console.WriteLine("ID has been queued for fetching");
}
catch (Exception ex)
{
Console.WriteLine("Error: " + ex.Message);
}
Console.ReadLine();
}
}
public static void Process(object state)
{
var s = StatsFecther("byId", "0"); //returns all player stats
Console.WriteLine("Account: " + s.nickname);
Console.WriteLine("ID: " + s.account_id);
Console.ReadLine();
}
我要做的是有大约50个线程(可能更多)获取包含玩家统计数据的序列化php数据。从用户0一直到我指定的用户ID(300,000)。我的问题不是关于如何获取我知道如何获取统计数据并读取它们的统计数据,但是我如何编写一个Threadpool来继续获取统计数据,直到它达到300,000个用户ID而不踩到其他线程的脚趾和在将数据库检索到数据库时保存统计信息。
答案 0 :(得分:3)
static int _globalId = 0;
public static void Process(object state)
{
// each queued Process call gets its own player ID to fetch
processId = InterlockedIncrement(ref _globalId);
var s = StatsFecther("byId", processId); //returns all player stats
Console.WriteLine("Account: " + s.nickname);
Console.WriteLine("ID: " + s.account_id);
Console.ReadLine();
}
这是最简单的事情。但远非最佳。您正在使用同步调用,您依靠ThreadPool来限制调用速率,您没有针对失败调用的重试策略,并且您的应用程序在错误条件下(当Web调用失败时)表现得非常糟糕。
首先,您应该考虑使用WebRequest的异步方法:BeginGetRequestStream(如果您发布并拥有请求正文)和/或BeginGetResponse。这些方法可以更好地扩展,并且您可以获得更高的吞吐量以减少CPU(如果后端可以保持正常运行)。
其次你应该考虑自我投掷。在类似的项目中,我使用了待处理的请求计数。成功之后,每次通话都会提交2个以上的电话,并以节奏计数为上限。如果失败,通话将不会提交任何内容。如果没有待处理的呼叫,则基于计时器的重试每分钟都会提交一个新呼叫。这样,您只需在服务停机时每分钟尝试一次,从而保护您自己的资源不受牵引力的影响,并且在服务启动时将吞吐量提高到最大值。
您还应该知道.Net框架将限制它对任何资源的可靠性。您必须找到目的地ServicePoint并将ConnectionLimit从其默认值(2)更改为您愿意限制的最大值。
关于数据库更新部分,有很多变量可供使用,而且信息太少,无法提供任何有意义的建议。一些一般的建议是在数据库调用中也使用异步方法,大小yoru连接池允许你的throtling上限,确保你的更新使用播放器ID作为键,这样你就不会死于从不同的线程更新相同的记录
答案 1 :(得分:0)
您如何确定用户ID?一种选择是对所有线程进行分段,以便线程X处理来自0 - N的ID,依此类推,作为您拥有的线程数的一小部分。