C # Thread Pooling Http веб-запросов
-
05-07-2019 - |
Вопрос
Я прочитал и посмотрел немало примеров для 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 и вплоть до указанного пользователем идентификатора пользователя (300 000). Мой вопрос не о том, как получить статистику, я знаю, как получить статистику и прочитать ее, а о том, как написать поток, который будет продолжать получать статистику до 300 000-го идентификатора пользователя, не наступая на пальцы других потоков и сохраняет статистику по мере извлечения их в базу данных.
Решение
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 для регулирования скорости вызовов, у вас нет политики повторных попыток для неудачных вызовов, и ваше приложение будет работать крайне плохо в условиях ошибки (при сбое веб-вызовов).
Прежде всего вам следует рассмотреть возможность использования асинхронных методов WebRequest: BeginGetRequestStream (если у вас POST и тело запроса) и / или BeginGetResponse . Эти методы масштабируются намного лучше, и вы получите более высокую пропускную способность при меньшем объеме процессора (если, конечно, серверная часть может справиться).
Во-вторых, вы должны подумать о самоуничтожении. В аналогичном проекте я использовал количество ожидающих запросов. В случае успеха каждый вызов отправляет еще 2 вызова, ограниченных счетчиком газа. В случае сбоя вызов не будет ничего отправлять. Если нет ожидающих вызовов, повторная попытка на основе таймера отправляет новый вызов каждую минуту. Таким образом, вы делаете попытку только один раз в минуту, когда служба не работает, сохраняя свои собственные ресурсы от вращения без тяги, и вы увеличиваете пропускную способность до уровня ограничения, когда служба работает.
Вы также должны знать, что .Net Framework будет ограничивать число одновременных согласований, которые оно делает, с любым ресурсом. Вы должны найти пункт назначения ServicePoint и изменить ConnectionLimit из значения по умолчанию (2 ) к максимальному значению, которое вы готовы задушить.
Что касается обновления базы данных, существует множество переменных и слишком мало информации, чтобы давать какие-либо содержательные советы. Некоторым общим советом было бы также использовать асинхронные методы в вызове базы данных, размер пула соединений, чтобы обеспечить ограничение скорости, убедитесь, что ваши обновления используют идентификатор игрока в качестве ключа, чтобы вы не зашли в тупик при обновлении одной и той же записи из разных потоков. . р>
Другие советы
Как вы определяете идентификатор пользователя? Один из вариантов - сегментировать все потоки так, чтобы поток X обрабатывал идентификаторы от 0 до N и т. Д., Как часть того, сколько у вас потоков.