Комментарии 24
А про легковесные потоки?
А про пулы потоков?
по запросу 'c# threads' в Гугле выдаст первую страницу с микрософта. чем ваша статья лучше их статьи ?
Например, тем, что эта статья статья размещена в блоге компании beeline cloud, и тем самым привлекает (хотя бы, теоретически) внимание к бренду этой компании ;-)
Вместо Thread'ов в C# сейчас рекомендуют использовать Task и асинхронные вызовы... Хотя лично мне Thread'ы понятнее (пусть даже и более громоздкие в реализации), чем всякие фокусы с синтаксисом...
Там отличия не только в синтаксисе, но и в том, что у задачи есть возвращаемое значение, а также возможность завершиться с исключением. В то же время у потока есть имя и приоритет.
Когда мне нужен именно отдельный поток - обычно я комбинирую его с задачей через TaskCompletionSource, чтобы получить преимущества обоих подходов.
Асинхронность и многопоточность, это абсолютно разные вещи... Так что ты не прав. Асинхронность может выполняться как в одном потоке, так и в нескольких потоках. И разные потоки могут иметь асинхронность. Почитай подробнее про разницу в этих понятиях и механизмах. Полезно будет
Есть мнение: thread - низкоуровневая концепция. Их при разработке лучше не использовать. Если потоков будет больше чем колличество ядер, то прикладные расходы (переключение контекста, фрагментакция памяти и т.д.) превысят всю пользу. По этому рекомендуют Task.
А эта рекомендация по количеству ядер относится к физическим или логическим ядрам процессора, которые возвращает тот же Environment.ProcessorCount
? По моим тестам всё же логическим, но возможно это истинно не для всех процессоров.
К логическим ядрам.
Смотреть на количество физических ядер имеет смысл когда Вы эти физические ядра в состоянии полностью загрузить (кеши, алу и пр.). Это бывает в числодробилках и подобном, и то если там бОльшая часть кода хорошо оптимизирована. В типовых бизнес приложениях, особенно, если использовать объекты и виртуальные вызовы, загрузить физические ядра не очень получается. Поэтому на количество логических ядер смотрят.
В типовых бизнес приложениях ... загрузить физические ядра не очень получается.
У MS Exchange - очень даже получается, судя по тому, что в указаниях по настройке сервера для него настоятельно рекомендуется отключать Hyperthreading.
Подозреваю, что подобное верно и для любых других СУБД: типично у них все потоми исполняют примерно один и тот же код, так что для них задействуются одни и те же исполнительные устройства проицессора и толку от распараллеливания его по разнороднымм исполнительным устройствам мало. Ну, и они создают много нагрузки на подсистему памяти - от локальных кэшей до RAM, - которую стараются использовать по максимуму под кэш содержимого БД.
Как говорил "великий человек":
Если у вас нет процессора, то к вас нет процессора.
Зависит от задачи. Потому что переключение контекста, когда потоки и так могут спать большую часть времени, не так сильно влияет. Но тут другой фактор, по-первых потоку надо выделять ресурсы, например, тот же стэк. Если часто создавать, то будет тратиться время на создание.
Я придерживаюсь, что если задача постоянная фоновая, то лучше напишу поток, который например делает опрос, инициирует сетевое общение для актуализации данных, чем буду городить это на Task-ах. И упаси делать LongRunning таски с циклом.
Thread имеют ещё полезную штуку как имена. Тоже удобно это устанавливать и в логах добавлять эту инфу.
Потому смотря где.
Для асинхронности и любой I/O операции и зависящих от неё, то конечно Task.
не оч. понятно почему, если мы говорим о C# (или .NET), рассматривается только Thread-вариант, а Task (и Parallel) даже не упомянуты ?..
Task это асинхронность, а Thread это многопоточность. Это разные вещи. В данной статье говорится про многопоточность.
Асинхронность может выполняться как в одном потоке, так и в нескольких. И так же, разные потоки могут иметь асинхронность отдельно.
Task это асинхронность, а Thread это многопоточность.
Wat? И давно это вдруг так стало? Т.е. Task.Run - запустит задачу асинхронно?
Да, запустит асинхронно. Потому что асинхронно значит - с отсутствием ожидания (busy waiting). Если мы берем вторую рабочую лошадку чтобы тянуть телегу (Task.Run), то первая может делать все что захочет (например везти другую телегу, а может и не везти, смотря что требуется). Подтяните своия знания в асинхронности.
Асинхронно значит несколько другое, отсутствие ожидание имеется в наличии и в параллельном коде и в асинхронном)) Кому тут нужно подтягивать знания - большой вопрос.
В контексте дефолтного планировщика Task.Run - запустит задачу параллельно и все что мы можем - это асинхронно дождаться ее выполнения. Т.е. в целом речь шла о том что Task и Thread нельзя четко разделить, что одно всегда асинхронное, а второе всегда параллельное.
Асинхронность в шарпе существовала и до появления async/await и даже до появления Task (APM и EAP жуткие штуки, но они имеют место быть)
Асинхронно значит несколько другое, отсутствие ожидание имеется в наличии и в параллельном коде и в асинхронном))
Все верно, потому что параллельное выполнение - это частный случай асинхронности. Асинхронность - наиболее фундаментальный термин. Почитайте хоть S.Cleary, что-ли.
Асинхронность значит ровно то, о чем было написано.
Т.е. в целом речь шла о том что Task и Thread нельзя четко разделить
Все тут можно разделить - у них совершенно разная ответственость, Task - это асинхронная операция (аналог promise-ов из js, или Future из Java/Rust), а Thread - это исполнитель (рабочая лошадка). У вас еще и SOLID-принципы хромают, судя по всему.
Task.Run - запустит задачу параллельно
Никто так не говорит, почитайте отцов-основателей Task-ов и async/await в С# (S.Toub-а, в частности) - говорят "запускается работа асинхронно". И никак иначе, терминологию надо использовать правильную. У вас легкая каша в голове.
Дам тебе прозвище Wat-балбес. ))
И давно это вдруг так стало?
Да, как бы, с самого начала.
Т.е. Task.Run - запустит задачу асинхронно?
То, как выполняется Task.Run
это полностью на усмотрение текущего task scheduler (который может быть даже полностью кастомный. Он может задачу вообще даже в вызываемом потоке синхронно выполнить, если решит, что так ему удобней.
По статье. Использовать Thread
так как у автора это вообще плохой и не рекомендуемый способ. Если уж так не хочется использовать Task
и надо выполнить что-то в другом потоке, то следует использовать ThreadPool.QueueUserWorkItem(...)
. Я когда статью читал, то всё думал, что, вот сейчас-то автор об этом скажет, а потом расскажет еще и про Task.Run(...)
, но тут статья внезапно и закончилась, так и не дойдя до этого.
То, как выполняется Task.Run это полностью на усмотрение текущего task scheduler (который может быть даже полностью кастомный.
Не зависит, Task.Run всегда использует планировщик по умолчанию. Вы путаете Run и StartNew
Согласен, что всегда планировщик по-умолчанию, ведь Task.Run - это более consumer-friendly версия аналога Task.Factory.StartNew.
// .NET9
public static Task Run(Action action)
{
return InternalStartNew(null, action, null, default, TaskScheduler.Default,
TaskCreationOptions.DenyChildAttach, InternalTaskOptions.None);
}
Из кода видно, что TaskScheduler.Default - так что без исключений, абсолютно всегда асинхронный вызов происходит. @nronnie
Многопоточность. Снизу вверх. Потоки в языке C#