Вопрос

Я прочитал и посмотрел немало примеров для 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 и т. Д., Как часть того, сколько у вас потоков.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top