Сведения о вопросе

Sadijon

03:04, 26th August, 2020

Теги

.net   multithreading    

Лучшая Практика Многопоточного Проектирования

Просмотров: 455   Ответов: 4

Рассмотрим эту проблему: у меня есть программа, которая должна получить (скажем) 100 записей из базы данных, а затем для каждой из них она должна получить обновленную информацию из веб-службы. Есть два способа ввести параллелизм в этом сценарии:

  1. Я запускаю каждый запрос к веб-службе в новом потоке. Количество одновременных потоков контролируется каким-то внешним параметром (или динамически настраивается каким-то образом).

  2. Я создаю меньшие партии (скажем, по 10 записей в каждой) и запускаю каждую партию в отдельном потоке (так что возьмем наш пример, 10 потоков).

Какой подход лучше, и почему вы так думаете?



  Сведения об ответе

repe

05:07, 23rd August, 2020

Вариант 3-самый лучший:

Используйте Async IO.

Если обработка ваших запросов не является сложной и тяжелой, ваша программа будет тратить 99% своего времени на ожидание HTTP запросов.

Это именно то, для чего предназначена Async IO - пусть сетевой стек windows (или фреймворк .net или что-то еще) беспокоится о всех ожиданиях и просто использует один поток для отправки и 'pick up' результатов.

К сожалению, фреймворк .NET делает его настоящей занозой в заднице. Это проще, если вы просто используете необработанные сокеты или Win32 api. Вот такой (проверенный!) пример использования C#3 в любом случае:

using System.Net; // need this somewhere

// need to declare an class so we can cast our state object back out
class RequestState {
    public WebRequest Request { get; set; }
}

static void Main( string[] args ) {
    // stupid cast neccessary to create the request
    HttpWebRequest request = WebRequest.Create( "http://www.stackoverflow.com" ) as HttpWebRequest;

    request.BeginGetResponse(
        /* callback to be invoked when finished */
        (asyncResult) => { 
            // fetch the request object out of the AsyncState
            var state = (RequestState)asyncResult.AsyncState; 
            var webResponse = state.Request.EndGetResponse( asyncResult ) as HttpWebResponse;

            // there we go;
            Debug.Assert( webResponse.StatusCode == HttpStatusCode.OK ); 

            Console.WriteLine( "Got Response from server:" + webResponse.Server );
        },
        /* pass the request through to our callback */
        new RequestState { Request = request }  
    );

    // blah
    Console.WriteLine( "Waiting for response. Press a key to quit" );
    Console.ReadKey();
}

EDIT:

В случае .NET 'completion callback' фактически запускается в потоке ThreadPool, а не в вашем основном потоке, поэтому вам все равно нужно будет заблокировать любые общие ресурсы, но это все равно избавит вас от всех проблем управления потоками.


  Сведения об ответе

COOL

10:25, 20th August, 2020

Тут нужно учитывать две вещи.

1. Сколько времени займет обработка записи?

Если обработка записей происходит очень быстро, накладные расходы на передачу записей потокам могут стать узким местом. В этом случае вы хотели бы иметь записи bundle, чтобы вам не приходилось передавать их так часто.

Если обработка записей достаточно длительна, разница будет незначительной, поэтому более простой подход (1 запись на поток), вероятно, является лучшим.

2. Сколько потоков вы планируете запустить?

Если вы не используете threadpool, я думаю, что вам нужно либо вручную ограничить количество потоков, либо разбить данные на большие куски. Запуск нового потока для каждой записи приведет к тому, что ваша система будет трястись, если количество записей станет большим.


  Сведения об ответе

PIRLO

03:49, 16th August, 2020

Компьютер, на котором работает программа, вероятно, не является узким местом, поэтому: Помните, что протокол HTTP имеет заголовок keep-alive, который позволяет отправлять несколько запросов GET на одни и те же сокеты, что избавляет вас от рукопожатия TCP/IP. К сожалению, я не знаю, как использовать это в библиотеках .net. (Должно быть возможным.)

Вероятно, также будет задержка с ответом на ваши запросы. Вы можете попробовать убедиться, что у вас всегда есть заданное количество невыполненных запросов к серверу.


  Сведения об ответе

DAAA

21:06, 1st October, 2020

Получить параллельное Форекс . Посмотрите на BlockingCollection. Используйте поток для подачи в него пакетов записей, а также от 1 до n потоков, вытягивающих записи из коллекции в сервис. Вы можете управлять скоростью подачи коллекции и количеством потоков, вызывающих веб-службы. Сделайте его настраиваемым через ConfigSection и сделайте его универсальным, подавая делегаты действия сбора, и у вас будет хороший маленький дозатор, который вы можете использовать в свое удовольствие.


Ответить на вопрос

Чтобы ответить на вопрос вам нужно войти в систему или зарегистрироваться