Здравствуйте, Karn, Вы писали:
K>Если вы посмотрите задание, решение и причины отказа, буду крайне благодарен. K>Просто на мой взгляд задание я выполнил неплохо, и мне интересно насколько глубоко я ошибаюсь.
В общем, по делу там в комментариях написано. В таких тестовых заданиях обычно смотрят не столько на крутизну использованных подходов, сколько на побочные эффекты, например, на то, как быстро посторонний сможет "въехать" в твоё решение. А в твоём случае довольно тяжело как уяснить сам код, так и прочесть пояснительную записку (каждое предложение "по традиции" приходится читать по три раза).
Относительно архитектуры присоединюсь к "предыдущему оратору": зачем здесь DI-контейнеры? Обычные ссылки были бы проще, а плюс к тому — ты показал бы как раз искомый OOP/OOD вместо искусства использования DI-контейнера. Зачем было огород городить? В общем, лучше бы ты потратил оставшееся время на предельное упрощение архитектуры и использованных решений, руководствуясь принципом: "если без вещи можно обойтись — она не нужна". Соответственно упростилось бы и всё остальное — от имён методов, до поясниловки и юнит-тестов.
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Здравствуйте, Karn, Вы писали:
K>Просто на мой взгляд задание я выполнил неплохо, и мне интересно насколько глубоко я ошибаюсь.
Посмотрел ваше задание и работу. У вас "болезнь начинающего программиста". Думаю, через это все в свое время прошли.
Когда только начинаешь -- хочешь применить все супер-модные технологии о которых только слышал, причем засунуть их везде -- и где можно и где неможна. Хочется максимально усложнить архитектуру, ввести десятки не особо нужных слоев-шелупаек...
А потом только осознаешь всю ценность простоты. Думаешь не как сделать крутую архитектуру -- а наоборот, как сделать МАКСИМАЛЬНО ПРОСТО и выбрать наиболее простые и подходящие решения.
Для простой задачи вы настолько усложнили решение, что даже я (более 7 лет опыта в .Net, и более 10 в программинге вообще) с налету нифига не понял. Мне кажется и ваш экзаменатор не до конца понял как оно все устроено. Ну зачем вы это делаете? А что если вам дать сложное задание? Кто тогда поймет что вы там написали?
И! Самое главное! В простейших вещах вы делаете грубейшие ошибки:
public virtual string GetSource(string address)
{
try
{
var request = WebRequest.Create(address) as HttpWebRequest;
if (request == null) return null; // Что это? Накой оно?var response = request.GetResponse() as HttpWebResponse;
if (response == null) return null; // Что это? Накой оно?using (var stream = response.GetResponseStream())
{
if (stream == null) return null; // Что это? Накой оно?using (var reader = new StreamReader(stream))
{
return reader.ReadToEnd();
}
}
}
catch (WebException)
{
// Нельзя прятать. Если, к примеру, страница не найдена (404) -- вы будете что делать (подсказка -- нужно вычеркнуть эту ссылку)? А если превышен интервал ожидания (подсказка -- повторить попытку)?
}
catch (Exception exception)
{
// То что вы написали этот блок говорит о том, что вы боитесь класса WebRequest. Вы не знаете как он работает. Ваша неуверенность заставила вписать здесь лишний код.
EnterpriseLibraryContainer.Current.GetInstance<LogWriter>().Write(exception);
throw;
}
return String.Empty; // Что это? В каком случае возникнет (подсказка -- при WebException)? Как вы это будете обрабатывать?
}
Здравствуйте, Karn, Вы писали:
K>Просто на мой взгляд задание я выполнил неплохо, и мне интересно насколько глубоко я ошибаюсь.
ИМХО, уж слишком многословно, отсюда и ошибки. Может быть, вас сбили упоминания DI и прочего в задании. По сути, требовалось два функционала — закачака/парсинг файлов и вывод результатов (тут я не совсем допёр, что значит "В последовательность файлов размером не более N Мбайт (конфигурируется)" — то есть вывод ссылк в последовательность файлов — им что ли нужен логер на подобии ролапа из log4net?).
Так вот, к заданию. Многопоточность вы там решили добавить — что ж, похвально. Только вот алгоритмы с
в топку. Ради чего? Неужели нельзя без колдунства?
Да и зачем вам собственные потоки? Чем стандартный пул не устроил? В нём достаточное количество потоков для работы на среднестатистическом компьютере. А, вообще, взяли бы таски, раз уж четвёртый фреймворк разрешили.
// если дошли до порога рекурсии - абортим все треды кроме той где
А ради чего требуется "доходить до порога рекурсии" и "абортить"? Почему нельзя, "дойдя до порога" просто не лезть в глубь, обработать всё на текущем уровне и успокоиться с чуством выполненого долга?
Совет: попробуйте реализовать задание используя минимальное количество кода, сущностей. Проведите декомпозию: ссылка/документ/ссылки/ссылка. Выделите в метод (а не в интерфейс + класс-реализация — у вас нет требований по расширяемости, зато есть требования по тестирабельности) решение подзадачи. Следите, что бы набор аргументов и возвращаемое значение были бы необходимыми и достаточными.
Ну и по мелочам не могу не докопаться: ссылки в документе всё же надо искать через DOM, а не простым сканом. Например, в значениях атрибутов элемиентов.
var request = WebRequest.Create(address) as HttpWebRequest;
if (request == null) return null;
var response = request.GetResponse() as HttpWebResponse;
if (response == null) return null;
using (var stream = response.GetResponseStream())
{
if (stream == null) return null;
using (var reader = new StreamReader(stream))
{
return reader.ReadToEnd();
}
}
Для чего там as и приведение типов вообще? Для чего проверки на null, то есть в каких случаях WebRequest.Create/request.GetResponse/response.GetResponseStream могут вернуть null? В документации об этом не говорится. Но даже если и так, то WebResponse надо диспозить в любом случае диспозить, даже если он вам и не подошёл вдруг.
В любом случае не расстраивайтесь: просто компании требовались какие-то другие особенности от кандидатов нежели те, что, они разглядели, как им показалось, в вас. Это же обычные смотрины с повезёт / не повезёт. Если компания так себе, то таких полно, обязательно найдёте свою. Если какая-то супер-очень… Ну представьте себе, что у вас случилось вдруг свидание со Скарлет Йохансон (или кто вам больше нравится?), а она на следующий день перезванивает и говорит: "Знаешь, больше не звони мне, мы не подходим друг другу." Ну совершенно это не стоит того, что бы огорчаться — она всё равно рассматривала тебя в качестве серьёздного кандидата
Help will always be given at Hogwarts to those who ask for it.
Надо же, тебе код-ревью на целую страницу написали, не поленились. Прогресс!..
В моем случае код-ревью выглядел так:
1. Процедурный стиль.
2. Небрежное использование асинхронных делегатов.
3. Отсутствие юнит тестов.
4. Плохие имена практически всех классов, методов, полей и переменных.
В переводе это означает:
1. Я должен был вместо одного класса с двумя методами (20 строк кода) сделать 10 классов с 50-ю методами. Как у тебя примерно.
2. Ревьювер не знал, что исключения в асинхронных делегатах регенерируются в EndInvoke(), и хотел увидеть тело метода обернутым в try{}catch(){}.
3. В солюшене из 3-х проектов ревьювер не нашел проекта с тестами. Ну не заметил просто. Ну бывает, хотел увидеть NUnit-тесты, а там MSTest оказался.
4. Эээ... не переводится
Я все это к чему: на Лабораторию Касперского нужно просто забить. Их просто ddos-ят. Ревьюверы просто не в состоянии переработать такое большое количество материала. Так что не огорчайся
Создать консольное windows-приложение (не прототип), выполняющее следующие задачи:
• Поиск всех ссылок типа http:// с html-страницы, адрес которой передан в качестве аргумента командной строки, а также со всех связанных с ней страниц (рекурсивно). Количество ссылок может достигать миллионов и более. Глубина рекурсии должна конфигурироваться.
• Вывод найденных уникальных ссылок по мере их обнаружения на консоль
• В последовательность файлов размером не более N Мбайт (конфигурируется)
...
Обязательно:
• Использование OOD/OOP
...
• ...VS2008/2010
Ну конечно, OOD это обязательно для парсера ссылок. А без Visual Studio 2010 так и вообще абсурд, браться за решение этой грандиозной задачи.
Здравствуйте, Karn, Вы писали:
K>после этого мне пришел ответ с отказом и комментариями тамошнего эксперта. Мне лично(наверное, больное самолюбие) комментарии K>к отказу показались недостаточно существенными. Если вы посмотрите задание, решение и причины отказа, буду крайне благодарен. K>Просто на мой взгляд задание я выполнил неплохо, и мне интересно насколько глубоко я ошибаюсь.
Да вообще не стоило делать это задание. Это где такое видано, чтобы столько времени тратить на задачу, ещё и неоплачиваемую, да и к тому же, не факт, что взяли бы на работу. Я бы $100 взял за реализацию. А тут бесплатно хотят в качестве тестового задания.
Здравствуйте, Karn, Вы писали:
K>Привет всем. Читаю тут время от времени про то, что людям вот дают тестовые задания. Нет, не так начну.. K>Решил я тут сходить на собеседование в одну компанию. Позиция — ведущий .NET разработчик. Позвонили, говорят: K>резюме неплохое у вас, но на эту позицию у нас предусмотрено тестовое задание небольшое, часов на 10-12. Не хотите? K>Я подумал — 10 часов не убудет и согласился, задание было действительно небольшим, я его сделал, отправил, через 4(!) часа K>после этого мне пришел ответ с отказом и комментариями тамошнего эксперта. Мне лично(наверное, больное самолюбие) комментарии K>к отказу показались недостаточно существенными. Если вы посмотрите задание, решение и причины отказа, буду крайне благодарен. K>Просто на мой взгляд задание я выполнил неплохо, и мне интересно насколько глубоко я ошибаюсь. K>1. Задание K>http://files.rsdn.ru/19230/task.txt K>2. Решение K>http://files.rsdn.ru/19230/HttpTraveller.zip K>3. Причины отказа K>http://files.rsdn.ru/19230/decline.txt
Сильно не разбирался, но семантика интерфейсов меня поставила в тупик
public interface IArchiveManager
{
bool IsAddressUniqueOnPrevious(string address);
void SendGenerationToStorage(string[] items, int storgeIndex);
}
долго думал, прежде чем предположил возможное поведение реализации. почему в интерфейс пролез номер хранилища, вроде как вещь сугубо завязана на имплементации, а не контракте.
Далее что-то очень похожее но не более понятное
public interface IGenerationStorage
{
bool IsAddressInStorage(string address, int storageIndex);
void DumpGenerationToStorage(string[] items, int storageIndex);
}
Опять мне надо ковыряться с каким-то непонятными номерами хранилищ в интерфейсе, при этом сущности отдельного хранилища нет.
Напрашивающихся абстракций документа, ссылки нет. Зато есть непонятные интерфейсы типа
Здравствуйте, _Raz_, Вы писали:
_FR>>Для чего проверки на null, _R_>Это все решарпер.
В инквизицию с такими оправданиями. У решарпера очень неплохо вроде как была размечена стандартная библиотека на этот счёт. Так что им надо багу написать.
_FR>>то есть в каких случаях WebRequest.Create/request.GetResponse/response.GetResponseStream могут вернуть null?
_R_> returnStream.Null;
_R_>То есть действительно может быть null;
Не поверите: не может. Изучите пожалуйста внимательнее данный вопрос. Вот "as" да, может вернуть в этом случае, но никаких проблем с этим быть не должно.
Help will always be given at Hogwarts to those who ask for it.
Здравствуйте, Karn, Вы писали:
K>...Позвонили, говорят: K>резюме неплохое у вас, но на эту позицию у нас предусмотрено тестовое задание небольшое, часов на 10-12. Не хотите? K>Я подумал — 10 часов не убудет и согласился, задание было действительно небольшим, я его сделал, отправил, через 4(!) часа K>после этого мне пришел ответ с отказом и комментариями тамошнего эксперта. Мне лично(наверное, больное самолюбие) комментарии K>к отказу показались недостаточно существенными.
Ну правильно, не надо было вообще делать это задание. Посыл таких существ на три буквы — самое правильное решение.
K>3. Причины отказа
Здравствуйте, placement_new, Вы писали:
_>Здравствуйте, TimurSPB, Вы писали:
TSP>>Ну конечно, OOD это обязательно для парсера ссылок. А без Visual Studio 2010 так и вообще абсурд, браться за решение этой грандиозной задачи.
_>мысла тестового задания ты так и не понял.
Да его тут как бы и нет. Что проверяет это тестовое задание совершенно не ясно. Умение писать простейшие регулярки? Знание что такое рекурсия и ее ограничения на практике? Наличие дома Windows с пиратской Визуал Студией?
Честно сказать, твое решение у меня вызвало шок. Нет, я конечно знал что дотнетчики страдают чрезмерным увлечением дизайном и архитектурой, но чтоб на столько.
Вобщем-то, данная задача решается в рамках простейшего приложения состоящего из 4-х основных + 5-10 вспомогательных функций:
чтение конфигурации;
загрузка страницы;
поиск ссылок ссылки на странице;
проверка найденной ссылки на уникальность.
Уж не знаю что за странные люди дали тебе эту задачу, и какие там ожидались ООП извраты, но это задача для 1-ого файла на ANSI-C.
Здравствуйте, kaa.python, Вы писали:
KP>Честно сказать, твое решение у меня вызвало шок. Нет, я конечно знал что дотнетчики страдают чрезмерным увлечением дизайном и архитектурой, но чтоб на столько. KP>Вобщем-то, данная задача решается в рамках простейшего приложения состоящего из 4-х основных + 5-10 вспомогательных функций: KP>чтение конфигурации; KP>загрузка страницы; KP>поиск ссылок ссылки на странице; KP>проверка найденной ссылки на уникальность. KP>Уж не знаю что за странные люди дали тебе эту задачу, и какие там ожидались ООП извраты, но это задача для 1-ого файла на ANSI-C.
У меня вообще-то тоже, несмотря на многолетний стаж дотнета. Принцип KISS универсален.
Разбиение на подзадачи неверное, кстати
0. Чтение конфигурации.
1. Загрузка страницы
2. Получение всех линков.
3. Отправка линков в некоторое хранилище, которое автоматом обеспечит их уникальность(напрашивается словарь, можно еще и частотный анализ линков прикрутить)
4. Spawn объектов(или потоков, хотя не факт, что наиболее эффективно) для повторения шагов 1-3 для каждого из полученных линков, пока не достигнута заданная глубина.
5. Вывод результатов в консоль.
6. Сохранение результатов в файл.
Т.е. примерно 5-6 основных сущностей надо. Многопоточность нужна только для шагов 1 и 2(пока скачивается страница, обрабатывать уже скачанные).
1м файлом тяжеловато будет решить. Или же полученный набор функций будет иметь весьма нетривиальную и запутанную логику.
Здравствуйте, StandAlone, Вы писали:
SA>Я понимаю твою нелюбовь к потокам — видимо, в чистом Си они тоже затруднены к использованию.
разочарую тебя. в чистом с нет: потоков, словарей, сетей
SA>Но в дотнете потоки легкодоступны и удобны. Поэтому все приложения, эффективно работающие с сетью — многопоточны. Это аксиома. SA>Асинхронное ИО к этому мало относится, всего лишь деталь реализации.
это потому, что ты абстрактно мыслишь. а на деле эффективней всего будет тащить одновременно сотни страниц. и как ты это в C# сделаешь?
Здравствуйте, StandAlone, Вы писали:
SA>Здравствуйте, kaa.python, Вы писали:
KP>>Нет, тут все синхронно. Ответ про асинхронность относился к тому, что сети и куча потоков вобщем-то крайне мало связаны.
SA>Так как синхронно-то? Вот ты получил первую страницу, начал ее обрабатывать.. и только после завершения обработки посылаешь запрос на вторую, а потом терпеливо ждешь, пока скачается? SA>А если обработка занимает больше времени, чем скачивание нескольких, тогда что? SA>Я понимаю твою нелюбовь к потокам — видимо, в чистом Си они тоже затруднены к использованию. SA>Но в дотнете потоки легкодоступны и удобны. Поэтому все приложения, эффективно работающие с сетью — многопоточны. Это аксиома. SA>Асинхронное ИО к этому мало относится, всего лишь деталь реализации.
kaa.python пытается сказать что не нужно использовать блокирующие операции и создавать для каждой поток. Вместо этого использовать асинхронные операции. Не дело плодить потоки лишь потому что они легкодоступны и удобны.
Здравствуйте, BulatZiganshin, Вы писали:
BZ>это потому, что ты абстрактно мыслишь. а на деле эффективней всего будет тащить одновременно сотни страниц. и как ты это в C# сделаешь?
Создам сотню объектов, каждый из которых тащит в отдельном потоке свою отдельную страницу, после завершения результат передается на обработку в парсер.
Парсер уже сам решает, как и сколькими потоками ему обрабатывать полученные результаты.
Здравствуйте, StandAlone, Вы писали:
SA>Как тут поможет асинхронное ИО, если, как правильно заметил Булат, скорость стягивания страниц может быть значительно выше скорости обработки?
В данном конкретном случае это гипотетическая и край маловероятная ситуация. Тем не менее, если она случится то один поток займется работой с сетью в асинхронном режиме, а второй займется парсингом.
Но, но, поток на страницу это отвратительное, жуткое, ужасное решение. Даже за одно это решение можно и нужно зарубить тестовое решение.
Здравствуйте, StandAlone, Вы писали:
SA>Здравствуйте, kaa.python, Вы писали:
KP>>Но, но, поток на страницу это отвратительное, жуткое, ужасное решение. Даже за одно это решение можно и нужно зарубить тестовое решение.
SA>Да почему? Под капотом поток вызвал методы сетевого апи — и ждет ответа, ресурсов процессора он не потребляет.
Кроме ресурсов процессора есть другие. И если бы потоки не потребляли ресурсов, нахрена бы стали делать пулы, и тем более асинхронные вызовы?
Привет всем. Читаю тут время от времени про то, что людям вот дают тестовые задания. Нет, не так начну..
Решил я тут сходить на собеседование в одну компанию. Позиция — ведущий .NET разработчик. Позвонили, говорят:
резюме неплохое у вас, но на эту позицию у нас предусмотрено тестовое задание небольшое, часов на 10-12. Не хотите?
Я подумал — 10 часов не убудет и согласился, задание было действительно небольшим, я его сделал, отправил, через 4(!) часа
после этого мне пришел ответ с отказом и комментариями тамошнего эксперта. Мне лично(наверное, больное самолюбие) комментарии
к отказу показались недостаточно существенными. Если вы посмотрите задание, решение и причины отказа, буду крайне благодарен.
Просто на мой взгляд задание я выполнил неплохо, и мне интересно насколько глубоко я ошибаюсь.
1. Задание http://files.rsdn.ru/19230/task.txt
2. Решение http://files.rsdn.ru/19230/HttpTraveller.zip
3. Причины отказа http://files.rsdn.ru/19230/decline.txt
Здравствуйте, _FRED_, Вы писали: _FR>Ну и по мелочам не могу не докопаться: ссылки в документе всё же надо искать через DOM, а не простым сканом. Например, в значениях атрибутов элемиентов.
Имхо регуляркой сильно быстрее, чем парсить миллионы документов ради ссылок.
Это тебе они кажутся несущественными, но ты не забывай, что ты выступаешь "одним из многих", соответственно, из общего числа кандидатов выбран был тот, у кого не было подобных замечаний.
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Ну да, вы все во многом правы (хотя не со всем я согласен Просто мне показалось, что замечания проверяющего не являются следствием каких-то догм и практик, а скорее следствием "его видения" того, как это должно быть реализовано и реальная "дельта" того что есть и того как должно не настолько значительна, чтобы отказываться от продолжения. Теперь я правда начинаю сомневаться в своем первом впечатлении
Здравствуйте, _FRED_, Вы писали:
_FR>Для чего проверки на null,
Это все решарпер.
_FR>то есть в каких случаях WebRequest.Create/request.GetResponse/response.GetResponseStream могут вернуть null?
/// <devdoc>
/// <para>Gets the stream used for reading the body of the response from the
/// server.</para>
/// </devdoc>public override Stream GetResponseStream() {
if(Logging.On)Logging.Enter(Logging.Web, this, "GetResponseStream", "");
CheckDisposed();
if (!CanGetResponseStream())
{
// give a blank stream in the HEAD case, which = 0 bytes of dataif(Logging.On)Logging.Exit(Logging.Web, this, "GetResponseStream", Stream.Null);
returnStream.Null;
}
if(Logging.On)Logging.PrintInfo(Logging.Web, "ContentLength="+m_ContentLength);
if(Logging.On)Logging.Exit(Logging.Web, this, "GetResponseStream", m_ConnectStream);
return m_ConnectStream;
}
public abstract class Stream : MarshalByRefObject, IDisposable
{
public static readonly Stream Null;
}
То есть действительно может быть null;
_FR>В документации об этом не говорится.
Здравствуйте, Karn, Вы писали:
K>Ну да, вы все во многом правы (хотя не со всем я согласен Просто мне показалось, что замечания проверяющего не являются следствием каких-то догм и практик, а скорее следствием "его видения" того, как это должно быть реализовано и реальная "дельта" того что есть и того как должно не настолько значительна, чтобы отказываться от продолжения. Теперь я правда начинаю сомневаться в своем первом впечатлении
Самый простой тест на качество кода — дать его прочесть кому то другому, если он не врубится как он в основном работает, значит есть проблемы. Код должен читаться, в Ваш код я например до конца так и не врубился. DI нужно в первую очередь что бы *построить* дерево объектов, а не пихать использование контейнера в каждый класс. В тестах зависимости строятся явным образом.
Здравствуйте, _FRED_, Вы писали:
_FR>Да и зачем вам собственные потоки? Чем стандартный пул не устроил? В нём достаточное количество потоков для работы на среднестатистическом компьютере. А, вообще, взяли бы таски, раз уж четвёртый фреймворк разрешили.
А если компьютер — 4х ядерный i7 c 24Gb ОП и 100Mb/c каналом, какое решение будет самым производительным в этой задаче? И допустим если усложнить — нужно в одной операции грузить не 1 страницу, а 5 например.
Здравствуйте, michael_isu, Вы писали:
_FR>>Да и зачем вам собственные потоки? Чем стандартный пул не устроил? В нём достаточное количество потоков для работы на среднестатистическом компьютере. А, вообще, взяли бы таски, раз уж четвёртый фреймворк разрешили.
_>А если компьютер — 4х ядерный i7 c 24Gb ОП и 100Mb/c каналом, какое решение будет самым производительным в этой задаче?
Это имеет какое-то отношение к использованию или нет пула?
_>И допустим если усложнить — нужно в одной операции грузить не 1 страницу, а 5 например.
Что значит "5 в одной операции"?
Help will always be given at Hogwarts to those who ask for it.
Здравствуйте, _FRED_, Вы писали:
_FR>Здравствуйте, michael_isu, Вы писали:
_FR>>>Да и зачем вам собственные потоки? Чем стандартный пул не устроил? В нём достаточное количество потоков для работы на среднестатистическом компьютере. А, вообще, взяли бы таски, раз уж четвёртый фреймворк разрешили.
_>>А если компьютер — 4х ядерный i7 c 24Gb ОП и 100Mb/c каналом, какое решение будет самым производительным в этой задаче?
_FR>Это имеет какое-то отношение к использованию или нет пула?
Вы сказали про среднестатистический компьютер, ну а я попытался привести пример несреднестатистического и хотелось узнать что тогда лучше использовать — пул или же собственные потоки.
_>>И допустим если усложнить — нужно в одной операции грузить не 1 страницу, а 5 например.
_FR>Что значит "5 в одной операции"?
Ну т.е. в методе, который выполняется в отдельном потоке, нужно загрузить не 1 страницу, а обойти по какому-то алгоритму несколько страниц сайта. Вопрос к тому, что будет лучше — каждый такой метод выполнять в своем потоке, либо же ещё и внутри метода каждую операцию загрузки страницы делать в отдельном потоке?
Здравствуйте, _FRED_, Вы писали:
_FR>В инквизицию с такими оправданиями. У решарпера очень неплохо вроде как была размечена стандартная библиотека на этот счёт. Так что им надо багу написать. http://youtrack.jetbrains.net/issue/RSRP-217580
Здравствуйте, michael_isu, Вы писали:
_FR>>>>Да и зачем вам собственные потоки? Чем стандартный пул не устроил? В нём достаточное количество потоков для работы на среднестатистическом компьютере. А, вообще, взяли бы таски, раз уж четвёртый фреймворк разрешили. _>>>А если компьютер — 4х ядерный i7 c 24Gb ОП и 100Mb/c каналом, какое решение будет самым производительным в этой задаче? _FR>>Это имеет какое-то отношение к использованию или нет пула? _>Вы сказали про среднестатистический компьютер, ну а я попытался привести пример несреднестатистического
Не среднестатистический — это сервер c огромным количеством процессоров. Бытовые компьютеры в этом плане все можно считать "среднестатистическими".
_>… и хотелось узнать что тогда лучше использовать — пул или же собственные потоки.
Собственные потоки нужны тогда, когда вам необходимо контролировать время жизни потока, какие-то его специфические свойства (приоритет, апартамент и прочее — менять эти параметры для "общих" потоков из пула — не красивый шаг). В данной же задачи требуется лишь выполнить какие-то действия в отдельном потоке. Что с этим потоком было до этих действий, что будет после — не так уж и важно.
_>>>И допустим если усложнить — нужно в одной операции грузить не 1 страницу, а 5 например. _FR>>Что значит "5 в одной операции"? _>Ну т.е. в методе, который выполняется в отдельном потоке, нужно загрузить не 1 страницу, а обойти по какому-то алгоритму несколько страниц сайта. Вопрос к тому, что будет лучше — каждый такой метод выполнять в своем потоке, либо же ещё и внутри метода каждую операцию загрузки страницы делать в отдельном потоке?
Если использовать высокоуровневые библиотеки, спроектированные как раз для таких задач — то разница (в програмировании) не велика. Это может зависеть от множества параметров: например, надёжности и скорости соединения (по которому закачиваются данные). думаю, в данной задачи большую часть времени будет занимать загрузка страницы. Насколько оптимальным и разумным вообще бедет попытка закачать одновременно пять-десять страниц заместот последовательной закачки каждой?
Если вернуться к примерному описанию задачи "ссылка/документ/ссылки/ссылка". "ссылка/документ" — это скачивание. Оно может быть последовательно (смотря, на сколько скачивание быстрее-медленнее разбора страницы) или параллельно, если у вас очень широкий канал. "документ/ссылки" — это парсинг. Тут имеет смысл распараллелить работу. Опять же хорошая библиотека сама за вас выберит оптимальное количество одновременно выполняющихся задач. "ссылки/ссылка" — логирование (например, так же по очереди, нет смысла параллельно писать в один файл).
В общем, если постараться и хорошо разбить задачу на подзадачи, то выбирать — параллельно или последовательно выполнять тот или иной кусок кода — это уже не сложно, главное что бы сам код задач небыл бы от этого [сильно] зависим. Таким образом решение заключается в правильном разбитии — а что с этим уже делать дальше — параллелить, тестировать, конфигурировать — становится второзначимым вопросом.
Help will always be given at Hogwarts to those who ask for it.
Спасибо.
_FR>Если использовать высокоуровневые библиотеки, спроектированные как раз для таких задач — то разница (в програмировании) не велика. Это может зависеть от множества параметров: например, надёжности и скорости соединения (по которому закачиваются данные). думаю, в данной задачи большую часть времени будет занимать загрузка страницы. Насколько оптимальным и разумным вообще бедет попытка закачать одновременно пять-десять страниц заместот последовательной закачки каждой?
Смысл есть, т.к. канал при загрузке страницы занимается не полностью, поэтому если одновременно грузить 100 страниц в 100 потоках — загрузятся все за не намногим большее время, чем если грузить 1 страницу.
Здравствуйте, Karn, Вы писали:
K>Привет всем. Читаю тут время от времени про то, что людям вот дают тестовые задания. Нет, не так начну.. K>Решил я тут сходить на собеседование в одну компанию. Позиция — ведущий .NET разработчик. Позвонили, говорят: K>резюме неплохое у вас, но на эту позицию у нас предусмотрено тестовое задание небольшое, часов на 10-12. Не хотите? K>Я подумал — 10 часов не убудет и согласился, задание было действительно небольшим, я его сделал, отправил, через 4(!) часа K>после этого мне пришел ответ с отказом и комментариями тамошнего эксперта. Мне лично(наверное, больное самолюбие) комментарии K>к отказу показались недостаточно существенными. Если вы посмотрите задание, решение и причины отказа, буду крайне благодарен. K>Просто на мой взгляд задание я выполнил неплохо, и мне интересно насколько глубоко я ошибаюсь. K>1. Задание K>http://files.rsdn.ru/19230/task.txt K>2. Решение K>http://files.rsdn.ru/19230/HttpTraveller.zip K>3. Причины отказа K>http://files.rsdn.ru/19230/decline.txt
Запихивание в подобные утилиты юнит-тестов и тем более контейнеров мне кажется разновидностью онанизма. В тестах больше кода, чем в самой программе. Мне недавно дали задание сделать практически то же самое с веб-мордой, получилось двести строк на Питоне, включая свой тред-пул, пока, правда, не ответили.
Здравствуйте, avpavlov, Вы писали: A>В тестах всегда больше кода, чем в тестируемой ф-ции. Если у тебя не так, то ты пишешь неправильные тесты.
Оно, конечно, понятно, что основной код должен быть выразительным, чтобы проще читать было, а тесты тупыми, чтобы не ломались, но блин.
_R_> public override Stream GetResponseStream() { _R_> if(Logging.On)Logging.Enter(Logging.Web, this, "GetResponseStream", ""); _R_> CheckDisposed();
_R_> if (!CanGetResponseStream()) _R_> { _R_> // give a blank stream in the HEAD case, which = 0 bytes of data _R_> if(Logging.On)Logging.Exit(Logging.Web, this, "GetResponseStream", Stream.Null); _R_> return Stream.Null; _R_> } _R_> if(Logging.On)Logging.PrintInfo(Logging.Web, "ContentLength="+m_ContentLength); _R_> if(Logging.On)Logging.Exit(Logging.Web, this, "GetResponseStream", m_ConnectStream); _R_> return m_ConnectStream;
Влезу и тоже попинаю — все эти if(Logging.On) Enter и Exit выглядят крайне неприятно. Лаконичность — одно из основных достоинств программиста. Не надо заслонять логику решаемых задач семантической избыточностью.
Надо как-то так
Здравствуйте, _FRED_, Вы писали:
_FR>Да и зачем вам собственные потоки? Чем стандартный пул не устроил? В нём достаточное количество потоков для работы на среднестатистическом компьютере. А, вообще, взяли бы таски, раз уж четвёртый фреймворк разрешили.
Иногда удобнее делать _secondaryThread.Join(), чем возиться с примитивами синхронизации в случае ThreadPool.QueueUserWorkItem
Здравствуйте, Karn, Вы писали:
K>резюме неплохое у вас, но на эту позицию у нас предусмотрено тестовое задание небольшое, часов на 10-12. Не хотите? K>Я подумал — 10 часов не убудет и согласился, задание было действительно небольшим, я его сделал, отправил, через 4(!) часа
2000 строк в 23-х .cs файлах. Извини меня, но за 4 часа такое сделать невозможно. Может быть, поэтому они тебе и отказали?
Здравствуйте, StandAlone, Вы писали:
_FR>>Да и зачем вам собственные потоки? Чем стандартный пул не устроил? В нём достаточное количество потоков для работы на среднестатистическом компьютере. А, вообще, взяли бы таски, раз уж четвёртый фреймворк разрешили.
SA>Иногда удобнее делать _secondaryThread.Join(), чем возиться с примитивами синхронизации в случае ThreadPool.QueueUserWorkItem
Это очень странный аргумент в пользу выбора того или иного инструмента: различия гораздо более фундаментальны, нежели простое "удобство" т ого или иного метода.
Help will always be given at Hogwarts to those who ask for it.
Здравствуйте, TimurSPB, Вы писали:
TSP>Ну конечно, OOD это обязательно для парсера ссылок. А без Visual Studio 2010 так и вообще абсурд, браться за решение этой грандиозной задачи.
Здравствуйте, alexeiz, Вы писали:
A>2000 строк в 23-х .cs файлах. Извини меня, но за 4 часа такое сделать невозможно. Может быть, поэтому они тебе и отказали?
Здравствуйте, AlexFox, Вы писали:
AF>Ну правильно, не надо было вообще делать это задание. Посыл таких существ на три буквы — самое правильное решение.
Трудно не согласиться.
Вот у этих наверняка не надо сушить мозги над тестовыми заданиями в 2000 строк объемом с неизвестным результатом:
если работает консультантом по стратегии и финансам, то может зарабатывать очень хорошо. около 5 т. евро в месяц, плюс бонус от проектов....
Компания, судя по всему, называется Маккинзи — следовательно, молодой человек получает от 200 до 300 тыс. рублей в месяц.
А, ему всего 24. Тогда его зарплата чуть ниже — около 150 тысяч. 200-300 — это уровень associate (после МБА или с опытом работы от 5 лет и выше).
скорее всего, он junior consultant
Если ему 24 и он начал работать сразу после окончания ВУЗа, то он уже не совсем junior. Начальная зарплата в Маккинзи — около 100 тысяч. Консультант со стажем 2 года (так называемый BA3) получает от 150 до 170.
Здравствуйте, StandAlone, Вы писали: SA>Трудно не согласиться. SA>Вот у этих наверняка не надо сушить мозги над тестовыми заданиями в 2000 строк объемом с неизвестным результатом:
Сарказм? Консультантов на собеседованиях дрючат намного круче, чем программистов.
AF>Ну правильно, не надо было вообще делать это задание. Посыл таких существ на три буквы — самое правильное решение.
Посыл кого-либо на три буквы в ответ на необязывающую просьбу (когда можно просто отказаться) гарантировано позволяет детектить сказочных чудаков на букву М.
Здравствуйте, avpavlov, Вы писали:
AF>>Ну правильно, не надо было вообще делать это задание. Посыл таких существ на три буквы — самое правильное решение.
A>Посыл кого-либо на три буквы в ответ на необязывающую просьбу (когда можно просто отказаться) гарантировано позволяет детектить сказочных чудаков на букву М.
Ага, вот и собеседующие, которые в дальнейшем запрещают людям слущать музыку за рабочей машиной.
Сказочных кого, говорите, позволяют детектировать такие задания?
SA>Ага, вот и собеседующие, которые в дальнейшем запрещают людям слущать музыку за рабочей машиной. SA>Сказочных кого, говорите, позволяют детектировать такие задания?
Такие задания позволяют детектировать компании, куда стоит или не стоит идти (в зависимости от предпочтений)
А вот посыл на три буквы позволяет детектировать сказочных ... ну и далее по тексту
Здравствуйте, kaa.python, Вы писали:
KP>Здравствуйте, placement_new, Вы писали:
_>>Здравствуйте, TimurSPB, Вы писали:
TSP>>>Ну конечно, OOD это обязательно для парсера ссылок. А без Visual Studio 2010 так и вообще абсурд, браться за решение этой грандиозной задачи.
_>>мысла тестового задания ты так и не понял.
KP>Да его тут как бы и нет. Что проверяет это тестовое задание совершенно не ясно. Умение писать простейшие регулярки? Знание что такое рекурсия и ее ограничения на практике? Наличие дома Windows с пиратской Визуал Студией?
Да я не об этом. Я о том, что раз комманда использует OOD, то и задание от них тоже надо делать в таком стиле, не важно хорош или плох этот подход.
Здравствуйте, Synapse, Вы писали:
S>По-моему, они дураки, что вас не взяли. Видно, что человек умеет писать хороший код и не писать плохой, а в этом и состоит наша профессия.
Они не дураки, они просто выдают Denial of Service. Наплыв "специалистов" слишком велик — сотни запросов в день. Я стопроцентно уверен, что ревью был скопипейстчен.
Здравствуйте, StandAlone, Вы писали:
SA>Т.е. примерно 5-6 основных сущностей надо. Многопоточность нужна только для шагов 1 и 2(пока скачивается страница, обрабатывать уже скачанные).
Хватит 5-ти функций, про файл я проморгал, каюсь Многопоточность не входит в рамки задачи и как следствие не нужна.
SA>1м файлом тяжеловато будет решить. Или же полученный набор функций будет иметь весьма нетривиальную и запутанную логику.
Да нормально это одним файлом решится, в крайнем случае на Си. cURL + например sglib для rb-дерева хватит за глаза. Задача слишком примитивна чтоб городить какие-то сущности и прочее.
Вобщем мне очень интересно было бы знать, в какой компании дают на столько странные тестовые задачи
Здравствуйте, kaa.python, Вы писали:
KP>Хватит 5-ти функций, про файл я проморгал, каюсь Многопоточность не входит в рамки задачи и как следствие не нужна.
Да как не нужна? Классика же. Интенсивная работа с сетью как бы явно намекает на то, что задачи скачивания лучше отдать в отдельные потоки, и завести еще один для обработки полученных результатов.
KP>Да нормально это одним файлом решится, в крайнем случае на Си. cURL + например sglib для rb-дерева хватит за глаза.
Эээ...а дерево тут зачем, пардону просю за тупость? Для хранения уникальных линков вполне хватит обычного словаря
KP>Задача слишком примитивна чтоб городить какие-то сущности и прочее.
Сущности нужны, как минимум, для separation of concerns и последующего тестирования.
Мне один коллега вообще предложил все решить одним циклом..
KP>Вобщем мне очень интересно было бы знать, в какой компании дают на столько странные тестовые задачи
Тут же пробегало название. Касперычи это, родимые.
Здравствуйте, StandAlone, Вы писали:
SA>Да как не нужна? Классика же. Интенсивная работа с сетью как бы явно намекает на то, что задачи скачивания лучше отдать в отдельные потоки, и завести еще один для обработки полученных результатов.
Ты либо не работал с сетью, либо что… Но в сети, в случае с клиентскими приложениями, случаи когдна нужна многопоточность можно по пальцам пересчитать. Почти всегда хватает асинхронного IO.
SA>Эээ...а дерево тут зачем, пардону просю за тупость? Для хранения уникальных линков вполне хватит обычного словаря
В sglib нет словаря. А чего-то такого же компактного но со словарем я сходу вспомнить не сумел.
SA>Мне один коллега вообще предложил все решить одним циклом..
Тоже вариант.
SA>Тут же пробегало название. Касперычи это, родимые.
Здравствуйте, michael_isu, Вы писали:
_>Смысл есть, т.к. канал при загрузке страницы занимается не полностью, поэтому если одновременно грузить 100 страниц в 100 потоках — загрузятся все за не намногим большее время, чем если грузить 1 страницу.
большую часть времени занимает вообще ping. вон у меня до москвы (1000 км) 20-40 мс, до америки на порядок больше
Здравствуйте, Synapse, Вы писали:
S>Запихивание в подобные утилиты юнит-тестов и тем более контейнеров мне кажется разновидностью онанизма. В тестах больше кода, чем в самой программе. Мне недавно дали задание сделать практически то же самое с веб-мордой, получилось двести строк на Питоне, включая свой тред-пул, пока, правда, не ответили.
приходит человек устраиваться водителем карьерного самосвала. ему говорят:
— резюме у вас отличное, но мы хотели бы дать вам тестовое задание
— давайте
— вы понимаете, что в карьер мы вас пустить не можем, поэтому продемонстрируйте своё умение водить БелАЗ, перевезя вот эту булавочку моей секретарше
сама суть тех знаний, которые ожидаются от ведущего, архитектора и т.д. — в том, что это знания, необходимые только на крупных проектах. на вышеупомянутую задачу можно посадить студента, и он её решит в 10 строчек ничего не зная об ооп или ют
и что ты предлагаешь — давать тест на 10 месяцев? :D поэтому тут необходимо проявить некоторое воображение и написать нечто подобное известному файлу в 50 строк, осуществляющему сложение двух чисел. и разумеется, у проверяющего тоже должно быть это понимание и ни малейших придирок к тому, что на 50 строк кода приходится 10 классов и 100 тестов
Здравствуйте, kaa.python, Вы писали:
KP>Ты либо не работал с сетью, либо что… Но в сети, в случае с клиентскими приложениями, случаи когдна нужна многопоточность можно по пальцам пересчитать. Почти всегда хватает асинхронного IO.
Бггг. Так асинхронный ИО тоже будет в том одном файлике?
SA>>Мне один коллега вообще предложил все решить одним циклом..
KP>Тоже вариант.
Здравствуйте, BulatZiganshin, Вы писали:
BZ>и что ты предлагаешь — давать тест на 10 месяцев? :D поэтому тут необходимо проявить некоторое воображение и написать нечто подобное известному файлу в 50 строк, осуществляющему сложение двух чисел. и разумеется, у проверяющего тоже должно быть это понимание и ни малейших придирок к тому, что на 50 строк кода приходится 10 классов и 100 тестов
ИМХО, это все равно не причина делать гусеничный велосипед с независимой торсионной подвеской. Разве что топикстартеру очень хотелось попрограммировать и нечем было больше заняться...
Или он спер это решение где-то в сети и мальца перелицевал под себя
Здравствуйте, StandAlone, Вы писали:
SA>Т.е. примерно 5-6 основных сущностей надо. Многопоточность нужна только для шагов 1 и 2(пока скачивается страница, обрабатывать уже скачанные).
hint: два мелких файла скачаются за то же время, что и один
если говорить об эффективном решении, то надо брать пул зелёных потоков, делать очередь http-запросов и очередь скачанных страниц. да и парсить страницы эффективней в несколько потоков на современных cpu
Здравствуйте, kaa.python, Вы писали:
KP>Ты либо не работал с сетью, либо что… Но в сети, в случае с клиентскими приложениями, случаи когдна нужна многопоточность можно по пальцам пересчитать. Почти всегда хватает асинхронного IO.
Здравствуйте, kaa.python, Вы писали:
KP>Нет, тут все синхронно. Ответ про асинхронность относился к тому, что сети и куча потоков вобщем-то крайне мало связаны.
Так как синхронно-то? Вот ты получил первую страницу, начал ее обрабатывать.. и только после завершения обработки посылаешь запрос на вторую, а потом терпеливо ждешь, пока скачается?
А если обработка занимает больше времени, чем скачивание нескольких, тогда что?
Я понимаю твою нелюбовь к потокам — видимо, в чистом Си они тоже затруднены к использованию.
Но в дотнете потоки легкодоступны и удобны. Поэтому все приложения, эффективно работающие с сетью — многопоточны. Это аксиома.
Асинхронное ИО к этому мало относится, всего лишь деталь реализации.
Здравствуйте, StandAlone, Вы писали:
SA>Т.е. примерно 5-6 основных сущностей надо. Многопоточность нужна только для шагов 1 и 2(пока скачивается страница, обрабатывать уже скачанные).
SA>1м файлом тяжеловато будет решить. Или же полученный набор функций будет иметь весьма нетривиальную и запутанную логику.
1) Завести фоновый парсер, скармливать ему задачи на разбор
2) Завести фоновый загрузчик, скармливать ему ссылки на закачку
3) В основном потоке в main крутить цикл с sleep в ожидании завершения всех закачек либо прерывания.
4 класса примерно, 4 сорца (если на java).
Вообще меня напугало обилие юнит-тестов- что там тестить на ровном месте?
Здравствуйте, BulatZiganshin, Вы писали:
BZ>Здравствуйте, kaa.python, Вы писали:
KP>>Ты либо не работал с сетью, либо что… Но в сети, в случае с клиентскими приложениями, случаи когдна нужна многопоточность можно по пальцам пересчитать. Почти всегда хватает асинхронного IO.
BZ>один из них — рекурсивная выкачка сайтов, нет?
Нет, по-уму, тут просто асинхронный IO и, возможно, но совсем не обязательно, еще один поток для парсинга результатов (в случае с Mac OS X либо FreeBSD я бы воспользовался GCD). С учетом того что в задании нет ни слова про потоки или параллельность работы то для данной задачи необходима просто синхронная работа в один поток.
Здравствуйте, ArtemGorikov, Вы писали:
AG>1) Завести фоновый парсер, скармливать ему задачи на разбор AG>2) Завести фоновый загрузчик, скармливать ему ссылки на закачку
типичный подход человека, который что-то слышал про оптимизацию. по факту это решение будет ничуть не быстрее прямолинейного, и десятки-сотни раз медленней правильного
Здравствуйте, StandAlone, Вы писали:
SA>Так как синхронно-то? Вот ты получил первую страницу, начал ее обрабатывать.. и только после завершения обработки посылаешь запрос на вторую, а потом терпеливо ждешь, пока скачается?
Да, именно. Ты где-то в задании видел иное требование? Не надо додумывать задачи сверх необходимого.
SA>А если обработка занимает больше времени, чем скачивание нескольких, тогда что?
В данном конкретном случае это практически не вероятно. Если же это будет иметь место, то ее нужно выделить в отдельный поток.
SA>Я понимаю твою нелюбовь к потокам — видимо, в чистом Си они тоже затруднены к использованию.
Я люблю потоки. Просто большинство не представляет как ими пользоваться и городит по потоку на каждый чих.
SA>Асинхронное ИО к этому мало относится, всего лишь деталь реализации.
Нет, это как раз очень важный момент, раз уж мы про сетевое приложение говорим.
Здравствуйте, BulatZiganshin, Вы писали:
BZ>Здравствуйте, StandAlone, Вы писали:
SA>>Я понимаю твою нелюбовь к потокам — видимо, в чистом Си они тоже затруднены к использованию.
BZ>разочарую тебя. в чистом с нет: потоков, словарей, сетей
SA>>Но в дотнете потоки легкодоступны и удобны. Поэтому все приложения, эффективно работающие с сетью — многопоточны. Это аксиома. SA>>Асинхронное ИО к этому мало относится, всего лишь деталь реализации.
BZ>это потому, что ты абстрактно мыслишь. а на деле эффективней всего будет тащить одновременно сотни страниц. и как ты это в C# сделаешь?
Через асинхронные вызовы http://msdn.microsoft.com/en-us/library/system.net.webrequest.begingetresponse.aspx
там с примером
Здравствуйте, StandAlone, Вы писали:
SA>Здравствуйте, BulatZiganshin, Вы писали:
BZ>>это потому, что ты абстрактно мыслишь. а на деле эффективней всего будет тащить одновременно сотни страниц. и как ты это в C# сделаешь?
SA>Создам сотню объектов, каждый из которых тащит в отдельном потоке свою отдельную страницу, после завершения результат передается на обработку в парсер.
А если 200 или 300?
Здравствуйте, samius, Вы писали:
S>kaa.python пытается сказать что не нужно использовать блокирующие операции и создавать для каждой поток. Вместо этого использовать асинхронные операции. Не дело плодить потоки лишь потому что они легкодоступны и удобны.
Так зачем плодить? Воспользоваться существующим пулом
Как тут поможет асинхронное ИО, если, как правильно заметил Булат, скорость стягивания страниц может быть значительно выше скорости обработки?
IOCompletionPort'ы будут ждать, пока этот самый единственный поток kaa.python-а не освободится.
Здравствуйте, StandAlone, Вы писали:
SA>Здравствуйте, samius, Вы писали:
S>>kaa.python пытается сказать что не нужно использовать блокирующие операции и создавать для каждой поток. Вместо этого использовать асинхронные операции. Не дело плодить потоки лишь потому что они легкодоступны и удобны.
SA>Так зачем плодить? Воспользоваться существующим пулом SA>Как тут поможет асинхронное ИО, если, как правильно заметил Булат, скорость стягивания страниц может быть значительно выше скорости обработки? SA>IOCompletionPort'ы будут ждать, пока этот самый единственный поток kaa.python-а не освободится.
Асинхронные операции вместо блокирующих. Причем тут единственный поток? Кто сказал единственный поток?
А, ты про это. Я что-то не прозреваю особой разницы, если честно. Что взять поток из пула и дать ему задание синхронно качать страницу, что дать вебреквесту задание и ждать, пока он не вызовет обработчик завершения задания, взяв для выполнения поток из того же пула.
Здравствуйте, kaa.python, Вы писали:
KP>Нет, по-уму, тут просто асинхронный IO и, возможно, но совсем не обязательно, еще один поток для парсинга результатов (в случае с Mac OS X либо FreeBSD я бы воспользовался GCD).
а, если ты не рассматриваешь aio как частный случай многопоточности...
но самый простой способ решения этой задачи, какой я знаю — использовать язык с green threads и автоматическим использованием aio "за сценой". дальше порождаем по потоку для каждой выкачки, ограничивая число активных потоков семафором в 1000 штук, результаты складываем в очередь, которая парсится 4 потоками. и всё. те же 10 строк, но работающих эффективно:
sem <- createSemaphore 1000
pages <- createChannel [startUrl]
for (1..4) $ \_ -> do
forkIO$ do
page <- getChannel pages
for (getUrls page) $ \url -> do
forkIO$ do
downSemaphore sem
page <- getURL url
putChannel pages page
upSemaphore sem
KP>С учетом того что в задании нет ни слова про потоки или параллельность работы то для данной задачи необходима просто синхронная работа в один поток.
ну это понятно, что дело религии. я выше говорил, что эту задачу можно решить в 10 строчек на любом языке, вот только продемонстрировать свои таланты при этом не удастся
Здравствуйте, StandAlone, Вы писали:
SA>Здравствуйте, samius, Вы писали:
S>>Через асинхронные вызовы S>>http://msdn.microsoft.com/en-us/library/system.net.webrequest.begingetresponse.aspx S>>там с примером
SA>А, ты про это. Я что-то не прозреваю особой разницы, если честно. Что взять поток из пула и дать ему задание синхронно качать страницу, что дать вебреквесту задание и ждать, пока он не вызовет обработчик завершения задания, взяв для выполнения поток из того же пула.
Это плохо. Надо прозреть.
В первом случае ты не сможешь одновременно тащить больше страниц чем потоков в пуле. Во втором случае потоки нужны будут лишь для того что бы принять ответ и запросить данные (не ждать), потом получить управление при получении данных.
Здравствуйте, samius, Вы писали:
S>kaa.python пытается сказать что не нужно использовать блокирующие операции и создавать для каждой поток. Вместо этого использовать асинхронные операции. Не дело плодить потоки лишь потому что они легкодоступны и удобны.
по твоему, ЯВУ используют только те, кто не знают асма?
Здравствуйте, BulatZiganshin, Вы писали:
BZ>Здравствуйте, ArtemGorikov, Вы писали:
AG>>1) Завести фоновый парсер, скармливать ему задачи на разбор AG>>2) Завести фоновый загрузчик, скармливать ему ссылки на закачку
BZ>типичный подход человека, который что-то слышал про оптимизацию. по факту это решение будет ничуть не быстрее прямолинейного, и десятки-сотни раз медленней правильного
—
1) Не слишком самоуверенно?
2) Предложите правильное решение.
P.S. Потоки еще не означают что будут блокировки- погуглите в направлении неблокирущих очередей.
P.S. 2 Фоновый загрузчик тоже может асинхронно качать- и при этом его обратные вызовы о завершении не будут ждать пока парсер завершит текущую операцию.
Здравствуйте, BulatZiganshin, Вы писали:
BZ>Здравствуйте, samius, Вы писали:
S>>kaa.python пытается сказать что не нужно использовать блокирующие операции и создавать для каждой поток. Вместо этого использовать асинхронные операции. Не дело плодить потоки лишь потому что они легкодоступны и удобны.
BZ>по твоему, ЯВУ используют только те, кто не знают асма?
я не знаю асма
Здравствуйте, kaa.python, Вы писали:
KP>Но, но, поток на страницу это отвратительное, жуткое, ужасное решение. Даже за одно это решение можно и нужно зарубить тестовое решение.
Да почему? Под капотом поток вызвал методы сетевого апи — и ждет ответа, ресурсов процессора он не потребляет.
А уже АПИ внутри себя использует асинхронный ИО. На мой взгляд, нормальная инкапсуляция.
Здравствуйте, StandAlone, Вы писали:
SA>Создам сотню объектов, каждый из которых тащит в отдельном потоке свою отдельную страницу, после завершения результат передается на обработку в парсер.
Здравствуйте, BulatZiganshin, Вы писали:
BZ>Здравствуйте, kaa.python, Вы писали:
KP>>Я люблю потоки. Просто большинство не представляет как ими пользоваться и городит по потоку на каждый чих.
BZ>всё зависит от того, почём ты их берёшь
BZ>в С зелёные потоки невозможны (в C# их вроде тоже нет?), поэтому ты стараешься расходовать их экономно. в эрланге и миллион потоков обычное дело
А задание было не на эрланге
В C# зеленых нет, а обычные дороги по ресурсам (но не по строчкам кода на создание)
Здравствуйте, StandAlone, Вы писали:
SA>Как тут поможет асинхронное ИО, если, как правильно заметил Булат, скорость стягивания страниц может быть значительно выше скорости обработки?
Булат вместе с КО утверждают, что даже при минимальной, 20 мс задержке на выкачке страницы, это будет раз в 1000 дольше, чем найти на ней все ссылки
Здравствуйте, BulatZiganshin, Вы писали:
BZ>Здравствуйте, samius, Вы писали:
BZ>>>по твоему, ЯВУ используют только те, кто не знают асма? S>>я не знаю асма
BZ>видимо, и логику тоже
Угу, не смог связать переход от асинхронных операций к асму
Здравствуйте, scale_tone, Вы писали:
_>По крайней мере, прав ли я насчет ddos-a интервьюеров?
Сложно сказать, если честно. Если бы ты был C++ разработчиком то никакого ddos-а нет. А .NET это некий другой мир, другие проекты и прочее. С учетом того что .NET разработчиков на рынке очень и очень много, то возможно ты прав.
Здравствуйте, BulatZiganshin, Вы писали: BZ>и что ты предлагаешь — давать тест на 10 месяцев?
Тут проверяется способность вообразить, что у тебя в кузове сотни нефти. Надо смотреть на умение кодить, а не высасывать из пальца абстракции. Про абстракции можно на собеседовании поговорить.
Здравствуйте, Synapse, Вы писали:
BZ>>и что ты предлагаешь — давать тест на 10 месяцев? S>Тут проверяется способность вообразить, что у тебя в кузове сотни нефти. Надо смотреть на умение кодить, а не высасывать из пальца абстракции.
мы точно про ведущего говорим?
S>Про абстракции можно на собеседовании поговорить.
Здравствуйте, 0K, Вы писали:
0K>Покурил. В общем то не плохо. Но не то, что требовалось. Здесь явно не принцип KISS. Я бы сделал намного проще при том же функционале.
Если бы меня попросили бесплатно поработать 10 часов, я бы отказался. Но глядя на этот код, очевидно, что роль ведущего программиста его автор выполнять не сможет. Ведущий программист (http://ru.wikipedia.org/wiki/%D0%92%D0%B5%D0%B4%D1%83%D1%89%D0%B8%D0%B9_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%81%D1%82) часто отвечает за архитектуру и обучение менее опытных сотрудников, а тут автора самого обучать надо. В чем тут дело, или в недостатке квалификации, или в том, что задачу на 10 часов ты наговнякал за 4, я не знаю. Мой совет — если не хочется тратить 10 часов на тестовое задание (а это вполне объяснимо) так и скажи работодателю. Потому что иначе результат будет немного предсказуемым, что ты в итоге и получил.
Здравствуйте, 0K, Вы писали:
0K>А можно у вас уточнить, сколько по времени вы выполняли это тестовое задание. Только честно.
0K>Просто аналогичный проект большинство оценили в 2 недели, а некоторые даже в 2 месяца...
Не надо путать проект и тестовое задание. В реальном проекте все задачи выполняются как минимум в 10 раз дольше.
Здравствуйте, vb-develop, Вы писали:
VD>Не надо путать проект и тестовое задание. В реальном проекте все задачи выполняются как минимум в 10 раз дольше.
Почему. В задании было сказано: "Создать консольное windows-приложение (не прототип), выполняющее следующие задачи".
10 раз -- это вы имеете в виду намеренное торможение процесса разработки, т.к. все равно больше не заплатят, или что?
Здравствуйте, vb-develop, Вы писали:
VD>Не надо путать проект и тестовое задание. В реальном проекте все задачи выполняются как минимум в 10 раз дольше.
А еще интересный момент. В первом сообщении автор заявляет, что делал проект 4-ре (!) часа. А делал он очень сложно. Там около 1000 строк. Получается он пишет 250 строчек в час или 2000 строк в день. Поверите?
Причем заметьте -- сам код довольно сложный. Он пишет не то что нужно -- требовалось написать проще. Но видимо мощь интеллекта не позволила ему даже такое простое задание решать просто -- пришлось написать кучу интерфейсов, все подключения делать через DI и прочая прочая
Здравствуйте, 0K, Вы писали:
0K>Почему. В задании было сказано: "Создать консольное windows-приложение (не прототип), выполняющее следующие задачи".
0K>10 раз -- это вы имеете в виду намеренное торможение процесса разработки, т.к. все равно больше не заплатят, или что?
Нет, конечно. Промышленный код, и код на выброс совершенно разные вещи. Что они понимали под не прототипом я не знаю, но тестовое задание есть тестовое задание, в том плане что результат его выполнения не пригоден для управления атомной подводной лодкой.
Здравствуйте, 0K, Вы писали:
0K>Здравствуйте, vb-develop, Вы писали:
VD>>Не надо путать проект и тестовое задание. В реальном проекте все задачи выполняются как минимум в 10 раз дольше.
0K>А еще интересный момент. В первом сообщении автор заявляет, что делал проект 4-ре (!) часа. А делал он очень сложно. Там около 1000 строк. Получается он пишет 250 строчек в час или 2000 строк в день. Поверите?
Я на днях тоже тестовое задание сделал. Причем не с целью устроиться на работу, а просто ради спортивного интереса сколько оно времени займет. Количество строк код не считал, но думаю не сильно меньше в пересчете на час работы получится.
0K>Причем заметьте -- сам код довольно сложный. Он пишет не то что нужно -- требовалось написать проще. Но видимо мощь интеллекта не позволила ему даже такое простое задание решать просто -- пришлось написать кучу интерфейсов, все подключения делать через DI и прочая прочая
Это я не комментировал, код его вообще не смотрел. У меня, например, в тестовом задании было явно прописано что нужно использовать DI.