Многопоточная отправка данных на сервер
От: Nikola78  
Дата: 27.09.12 21:01
Оценка:
Есть windows сервис. Используется для обновления списка своих товаров на торговой площадке: он следит за файлом с помощью FileSystemWatcher и как только тот пояляется, он его читает и отправляет запросы в API интерфейс на сервер.

Я сделал его многопоточным, установил кол-во потоков равным 15. Не знаю почему именно столько и не знаю, много ли это или мало. Однако он работает.
Вот метод отправки данных на сервер.

Идея такова:
— если записей в файле меньше, чем кол-во потоков, то проходится по каждой записи и создаем один поток и отправляем данные.
— если записей в файле больше, чем кол-во потовов, то отправляем данные порциями по 15 (кол-во потоков).


private void Request(IEnumerable<Info> items)
        {
            Info[] infoArray = items.ToArray();
            Thread[] threads = new Thread[MaxCount];
            bool isPartialSending = info.Length > MaxCount;
            int deltaIndex = 0;
            for (int i = 0; i < info.Length; i++)
            {
                if (isPartialSending)
                {
                    if (i != 0 && i % MaxCount == 0)
                    {
                        Wait(threads);
                        deltaIndex = MaxCount * (i / MaxCount);
                    }
                }

                Info info = infoArray[i];
                threads[i - deltaIndex] = new Thread(_ => info.ReviceItem(apiContext));
                threads[i - deltaIndex].Start();
            }

            Wait(threads);
        }

        private static void Wait(IEnumerable<Thread> threads)
        {
            foreach (var thread in threads.Where(t => t != null))
            {
                thread.Join();
            }
        }


Как мне кажется, тут довольная низкая производительность: сначала он ест 2Кб. Если добавить файл в директорию, то он начинает есть 50Кб.
К тому же, файл с 20 записями весит около 0,5Кб. Если будет весить около 1Мб, то в нем будет много тысяч записей. Их все их нужно будет отправлять порциями по 15 шт.

К тому же, если кол-во записей в файле меньше чем 15 (MaxCount), то все равно я создаю 15 потоков. Я не придумал как это обойти: если использовать List, то тогда нельзя будет обратиться по индексу. И стоит ли вообще это пытаться обойти?


Правильная ли реализация для такой задачи?
Сколько все-таки должно быть потоков?
Как улучшить производительность?
Re: Многопоточная отправка данных на сервер
От: okman Беларусь https://searchinform.ru/
Дата: 28.09.12 05:48
Оценка:
Здравствуйте, Nikola78, Вы писали:

N>Есть windows сервис. Используется для обновления списка своих товаров на торговой площадке: он следит за файлом с помощью FileSystemWatcher и как только тот пояляется, он его читает и отправляет запросы в API интерфейс на сервер.


N>Я сделал его многопоточным, установил кол-во потоков равным 15. Не знаю почему именно столько и не знаю, много ли это или мало. Однако он работает.


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

Вот если на компьютере несколько сетевых интерфейсов, тогда да, можно попробовать через
каждый интерфейс пускать разные порции данных. Тогда, может, и будет смысл.

N>Вот метод отправки данных на сервер.


N>Идея такова:

N> — если записей в файле меньше, чем кол-во потоков, то проходится по каждой записи и создаем один поток и отправляем данные.
N> — если записей в файле больше, чем кол-во потовов, то отправляем данные порциями по 15 (кол-во потоков).

N>...


И что, на каждую запись приходится создавать отдельный HTTP-запрос ? Так это ведь ужасно,
учитывая их малый объем. По TCP-трафику получится многократный оверхед.

N>Как мне кажется, тут довольная низкая производительность: сначала он ест 2Кб. Если добавить файл в директорию, то он начинает есть 50Кб.

N>К тому же, файл с 20 записями весит около 0,5Кб. Если будет весить около 1Мб, то в нем будет много тысяч записей. Их все их нужно будет отправлять порциями по 15 шт.

Мегабайтовый файл можно отправить на сервер в одном потоке за несколько секунд. Подумайте об этом.
Re: Многопоточная отправка данных на сервер
От: GGoga  
Дата: 28.09.12 08:57
Оценка:
Здравствуйте, Nikola78, Вы писали:

N>...

N>если использовать List, то тогда нельзя будет обратиться по индексу
N>...

Смутило выделенное. List нормально работает с индексами:

List<int> myList = new List<int>() { 1, 10, 20, 30, 100 };
for (int i = 0; i < 2; i++)
{
   for (int j = 0; j < myList.Count; j++)
   {
      Console.WriteLine(myList[j]);
      myList[j] = myList[j] * j;
   }
}
Re[2]: Многопоточная отправка данных на сервер
От: Nikola78  
Дата: 28.09.12 10:42
Оценка:
Здравствуйте, okman, Вы писали:

O>Здравствуйте, Nikola78, Вы писали:


O>Потоки хороши, когда они могут распараллелить задачу, не мешая друг другу.

O>В данном случае смысла в большом количестве потоков нет. Сеть-то все равно одна и потоки
O>будут "толпиться в дверях", мешая друг другу в ожидании своей очереди.
O>Можете сделать хоть сто потоков — отправка не будет быстрее.

Странно. А как download master: он может и не создает потоки, но как-то закачивает одновременно.
Значит, не нужно создавать потоков вообще?

O>Вот если на компьютере несколько сетевых интерфейсов, тогда да, можно попробовать через

O>каждый интерфейс пускать разные порции данных. Тогда, может, и будет смысл.

Думаю, будет много заморочек.

N>>Вот метод отправки данных на сервер.


N>>Идея такова:

N>> — если записей в файле меньше, чем кол-во потоков, то проходится по каждой записи и создаем один поток и отправляем данные.
N>> — если записей в файле больше, чем кол-во потовов, то отправляем данные порциями по 15 (кол-во потоков).


O>Мегабайтовый файл можно отправить на сервер в одном потоке за несколько секунд. Подумайте об этом.

Мне не нужно отправлять файл. Мне нужно сделать столько запросов к api, сколько записей в файле.
Re[2]: Многопоточная отправка данных на сервер
От: Nikola78  
Дата: 28.09.12 10:43
Оценка:
Здравствуйте, GGoga, Вы писали:

GG>Здравствуйте, Nikola78, Вы писали:


N>>...

N>>если использовать List, то тогда нельзя будет обратиться по индексу
N>>...

GG>Смутило выделенное. List нормально работает с индексами:


GG>
GG>List<int> myList = new List<int>() { 1, 10, 20, 30, 100 };
GG>for (int i = 0; i < 2; i++)
GG>{
GG>   for (int j = 0; j < myList.Count; j++)
GG>   {
GG>      Console.WriteLine(myList[j]);
GG>      myList[j] = myList[j] * j;
GG>   }
GG>}
GG>


Действительно.
Re[2]: Многопоточная отправка данных на сервер
От: Nikola78  
Дата: 28.09.12 13:09
Оценка:
Здравствуйте, okman, Вы писали:



O>И что, на каждую запись приходится создавать отдельный HTTP-запрос ? Так это ведь ужасно,

O>учитывая их малый объем. По TCP-трафику получится многократный оверхед.

Тогда как еще можно?
Re[3]: Многопоточная отправка данных на сервер
От: okman Беларусь https://searchinform.ru/
Дата: 28.09.12 13:23
Оценка:
Здравствуйте, Nikola78, Вы писали:

N>Странно. А как download master: он может и не создает потоки, но как-то закачивает одновременно.


Да, одновременно. Но со скоростью, обратно пропорциональной количеству одновременных закачек.

N>Значит, не нужно создавать потоков вообще?


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

N>Мне не нужно отправлять файл. Мне нужно сделать столько запросов к api, сколько записей в файле.


15 потоков для этого не нужны.
Если речь про HTTP, можете поэкспериментировать с request pipelining — это когда несколько
запросов отправляются один за другим, пакетно, а затем обрабатывается такой же пакет ответов сервера.
Re[3]: Многопоточная отправка данных на сервер
От: okman Беларусь https://searchinform.ru/
Дата: 28.09.12 13:35
Оценка:
Здравствуйте, Nikola78, Вы писали:

O>>И что, на каждую запись приходится создавать отдельный HTTP-запрос ? Так это ведь ужасно,

O>>учитывая их малый объем. По TCP-трафику получится многократный оверхед.

N>Тогда как еще можно?


Можно по-разному, но это все имеет смысл лишь в том случае, если у Вас есть доступ к
коду сервера или возможность влиять на логику его работы.
Вместо отдельного запроса на каждую запись, — а там ведь счет на тысячи, — лучше было бы
отправлять записи пачками. Например, по тысяче штук в одном запросе или вообще все сразу.

Давайте посчитаем.
Одна запись — это примерно 25 байт.
Еще столько же — на статусную строку HTTP.
На HTTP-заголовки уйдет еще минимум полсотни байт, даже если взять только самые необходимые.
Приплюсуем сюда ответы сервера на каждый запрос. Пускай будет еще 25 байт, хотя это все очень
оптимистические расценки. Вот и получается, что на десять мегабайт полезного трафика будет
приходиться пятьдесят мегабайт балласта в виде HTTP-заголовков, статусных строк и символов CRLF.
Re[4]: Многопоточная отправка данных на сервер
От: Nikola78  
Дата: 28.09.12 13:44
Оценка:
Здравствуйте, okman, Вы писали:

O>Здравствуйте, Nikola78, Вы писали:


O>>>И что, на каждую запись приходится создавать отдельный HTTP-запрос ? Так это ведь ужасно,

O>>>учитывая их малый объем. По TCP-трафику получится многократный оверхед.

N>>Тогда как еще можно?


O>Можно по-разному, но это все имеет смысл лишь в том случае, если у Вас есть доступ к

O>коду сервера или возможность влиять на логику его работы.

Такой возможности нет, это ebay. Прийдется отправлять по одному?
Re[4]: Многопоточная отправка данных на сервер
От: Nikola78  
Дата: 28.09.12 14:13
Оценка:
Здравствуйте, okman, Вы писали:

O>Здравствуйте, Nikola78, Вы писали:


O>>>И что, на каждую запись приходится создавать отдельный HTTP-запрос ? Так это ведь ужасно,

O>>>учитывая их малый объем. По TCP-трафику получится многократный оверхед.

N>>Тогда как еще можно?


O>Можно по-разному, но это все имеет смысл лишь в том случае, если у Вас есть доступ к

O>коду сервера или возможность влиять на логику его работы.

Такой возможности нет, это ebay. Прийдется отправлять по одному
Re[5]: Многопоточная отправка данных на сервер
От: okman Беларусь https://searchinform.ru/
Дата: 28.09.12 17:16
Оценка:
Здравствуйте, Nikola78, Вы писали:

O>>Можно по-разному, но это все имеет смысл лишь в том случае, если у Вас есть доступ к

O>>коду сервера или возможность влиять на логику его работы.

N>Такой возможности нет, это ebay. Прийдется отправлять по одному?


Да.
Re[4]: Многопоточная отправка данных на сервер
От: romca  
Дата: 30.09.12 07:27
Оценка: +1
Здравствуйте, okman, Вы писали:

O>Здравствуйте, Nikola78, Вы писали:


N>>Странно. А как download master: он может и не создает потоки, но как-то закачивает одновременно.


O>Да, одновременно. Но со скоростью, обратно пропорциональной количеству одновременных закачек.


Верно если время реакции сервера на запрос равно нулю и сервер не ограничевает скорость каждой закачки.
Re[5]: Многопоточная отправка данных на сервер
От: TK Лес кывт.рф
Дата: 30.09.12 08:40
Оценка:
Здравствуйте, Nikola78, Вы писали:

O>>Можно по-разному, но это все имеет смысл лишь в том случае, если у Вас есть доступ к

O>>коду сервера или возможность влиять на логику его работы.

N>Такой возможности нет, это ebay. Прийдется отправлять по одному


Если это HTTP то, ServicePointManager.DefaultConnectionLimit предполагает только два одновременных подключения.
Если у Вас нет паранойи, то это еще не значит, что они за Вами не следят.
Re[3]: Многопоточная отправка данных на сервер
От: TK Лес кывт.рф
Дата: 30.09.12 08:43
Оценка:
Здравствуйте, Nikola78, Вы писали:

N>Странно. А как download master: он может и не создает потоки, но как-то закачивает одновременно.

N>Значит, не нужно создавать потоков вообще?

Можно использовать асинхронность. Отдельный поток который будет сидеть и ждать завершения Send в большинстве случаев не нужен.
Если у Вас нет паранойи, то это еще не значит, что они за Вами не следят.
Re[4]: Многопоточная отправка данных на сервер
От: Nikola78  
Дата: 30.09.12 11:08
Оценка:
Здравствуйте, TK, Вы писали:

TK>Здравствуйте, Nikola78, Вы писали:


N>>Странно. А как download master: он может и не создает потоки, но как-то закачивает одновременно.

N>>Значит, не нужно создавать потоков вообще?

TK>Можно использовать асинхронность. Отдельный поток который будет сидеть и ждать завершения Send в большинстве случаев не нужен.


Я пока сделал вернулся к простой отправке запросов друг за другом.
Я не понимаю разницу между между асинхронностью и многопоточностью, в чем она и как ее здесь можно использовать?
Re[6]: Многопоточная отправка данных на сервер
От: Nikola78  
Дата: 30.09.12 11:10
Оценка:
Здравствуйте, TK, Вы писали:

TK>Здравствуйте, Nikola78, Вы писали:


O>>>Можно по-разному, но это все имеет смысл лишь в том случае, если у Вас есть доступ к

O>>>коду сервера или возможность влиять на логику его работы.

N>>Такой возможности нет, это ebay. Прийдется отправлять по одному


TK>Если это HTTP то, ServicePointManager.DefaultConnectionLimit предполагает только два одновременных подключения.


https
Re[5]: Многопоточная отправка данных на сервер
От: romca  
Дата: 30.09.12 12:55
Оценка:
Здравствуйте, Nikola78, Вы писали:

N>Здравствуйте, TK, Вы писали:


TK>>Здравствуйте, Nikola78, Вы писали:


N>>>Странно. А как download master: он может и не создает потоки, но как-то закачивает одновременно.

N>>>Значит, не нужно создавать потоков вообще?

TK>>Можно использовать асинхронность. Отдельный поток который будет сидеть и ждать завершения Send в большинстве случаев не нужен.


N>Я пока сделал вернулся к простой отправке запросов друг за другом.

N>Я не понимаю разницу между между асинхронностью и многопоточностью, в чем она и как ее здесь можно использовать?

И то и это многопоточность, асинхронность при правильном использовании, позволяет избежать простоя потока в ожидании какого ни будь ресурса, и с экономить поток для других вычислений, т.е. выполнять больше задач параллельно(реально конечно псевдопараллельно).
Re[6]: Многопоточная отправка данных на сервер
От: Nikola78  
Дата: 01.10.12 16:52
Оценка:
Здравствуйте, romca, Вы писали:

R>Здравствуйте, Nikola78, Вы писали:


N>>Здравствуйте, TK, Вы писали:


TK>>>Здравствуйте, Nikola78, Вы писали:


N>>>>Странно. А как download master: он может и не создает потоки, но как-то закачивает одновременно.

N>>>>Значит, не нужно создавать потоков вообще?

TK>>>Можно использовать асинхронность. Отдельный поток который будет сидеть и ждать завершения Send в большинстве случаев не нужен.


N>>Я пока сделал вернулся к простой отправке запросов друг за другом.

N>>Я не понимаю разницу между между асинхронностью и многопоточностью, в чем она и как ее здесь можно использовать?

R>И то и это многопоточность, асинхронность при правильном использовании, позволяет избежать простоя потока в ожидании какого ни будь ресурса, и с экономить поток для других вычислений, т.е. выполнять больше задач параллельно(реально конечно псевдопараллельно).


Не обязательно асинхронность — это многопоточность.
К тому же это очень расплывчато. чем мне поможет знание этого?
Re[4]: Многопоточная отправка данных на сервер
От: Nikola78  
Дата: 01.10.12 16:53
Оценка:
Здравствуйте, TK, Вы писали:

TK>Здравствуйте, Nikola78, Вы писали:


N>>Странно. А как download master: он может и не создает потоки, но как-то закачивает одновременно.

N>>Значит, не нужно создавать потоков вообще?

TK>Можно использовать асинхронность. Отдельный поток который будет сидеть и ждать завершения Send в большинстве случаев не нужен.

Как все-таки ее здесь использовать?
Re[5]: Многопоточная отправка данных на сервер
От: TK Лес кывт.рф
Дата: 02.10.12 17:45
Оценка:
Здравствуйте, Nikola78, Вы писали:

TK>>Можно использовать асинхронность. Отдельный поток который будет сидеть и ждать завершения Send в большинстве случаев не нужен.

N>Как все-таки ее здесь использовать?

Зависит от того, как вы отправляете данные на сервер. Например, для WebRequest есть WebRequest.GetRequestStreamAsync()
Можно составить цепочку типа:

public async Task SendData(data)
{
   using (var stream = await request.GetRequestStreamAsync())
   {
      await stream.WriteAsync(...);
   }
}


и после этого создать запросы и ждать выполнения:
Task.Factory.ContinueWhenAll(new [] { SendData(data1), SendData(data2) }, results => {});
Если у Вас нет паранойи, то это еще не значит, что они за Вами не следят.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.