Чи бувають випадки, коли бажано використовувати звичайний об’єкт Old Thread замість однієї з нових конструкцій?


112

Я бачу дуже багато людей у ​​публікаціях блогу, і тут на ПЗ або уникають або не рекомендують використовувати Threadклас в останніх версіях C # (і я маю на увазі, звичайно, 4.0+, з додаванням Task& друзів). Ще раніше були дискусії про те, що функціональність звичайної старої нитки в багатьох випадках може бути замінена ThreadPoolкласом.

Крім того, інші спеціалізовані механізми роблять Threadклас менш привабливим, наприклад, Timers замінює потворні Thread+ Sleepкомбі, тоді як для графічних інтерфейсів у нас є BackgroundWorkerі т.д.

Тим не менше, Threadсхоже, залишається дуже звичною концепцією для деяких людей (включаючи мене), людей, які, стикаючись із завданням, яке передбачає якесь паралельне виконання, переходять безпосередньо до використання старого доброго Threadкласу. Мене останнім часом цікавить, чи пора виправляти свої способи.

Отже, моє запитання: чи є випадки, коли потрібно або корисно використовувати звичайний старий Threadоб'єкт замість однієї з перерахованих конструкцій?


4
Не для nitpick (а може бути ... :)), але це .NET (тобто не обмежується C #).
MetalMikester

11
Поки що середній представник для користувача, який відповідає на це питання 64.5k. Досить вражаючий показ
zzzzBov

1
@zzzzBov: Я думав над тим, як опублікувати власну відповідь, але тепер не можу побоюватися знизити середнє значення :)
Брайан Гедеон

@BrianGideon, я не бачу причин, чому це не повинно зупинити вас або когось іншого у відповіді на це запитання.
zzzzBov

@Brian Gideon: Будь ласка, напишіть. :)
Тудор

Відповіді:


107

Клас Thread не може бути застарілим, оскільки, очевидно, це деталізація реалізації всіх інших згаданих вами зразків.

Але це насправді не ваше питання; ваше запитання

чи бувають випадки, коли потрібно або корисно використовувати звичайний старий об’єкт Thread замість однієї з вищезазначених конструкцій?

Звичайно. Саме в тих випадках, коли одна з конструкцій вищого рівня не відповідає вашим потребам.

Моя порада полягає в тому, що якщо ви опинитесь у ситуації, коли існуючі інструменти з вищою абстракцією не відповідають вашим потребам, і ви хочете реалізувати рішення за допомогою ниток, то вам слід визначити відсутню абстракцію, яка вам справді потрібна , а потім застосувати цю абстракцію використовуючи нитки , а потім використовуйте абстракцію .


33
Всі добрі поради. Але чи є у вас приклад, коли звичайний об’єкт старого потоку може бути кращим перед однією з нових конструкцій?
Роберт Харві

Налагодження декількох потоків із тимчасовими проблемами для завантаження якогось коду можна зробити набагато простіше, ніж тоді, використовуючи інші конструкції «вищого рівня». І вам потрібні базові знання роботи та використання теми.
CodingBarfield

Дякую за відповідь, Еріку. Під час нещодавнього обстрілу про нові функції різьблення дуже просто забути, що іноді стара нитка все ж потрібна. Ну, мабуть, знання про голий метал все-таки корисно мати.
Тудор

15
@RobertHarvey: Звичайно. Наприклад, якщо у вас є класична ситуація "виробник / споживач", коли ви хочете мати один потік, присвячений виведенню речей із черги робіт, та інший потік, призначений для розміщення матеріалів у черзі роботи. Обидві петлі назавжди; вони не чітко відображають завдання, які ви виконуєте певний час, а потім отримуєте результат. Вам не потрібен пул потоків, оскільки є лише дві нитки. І ви можете бути розумними у використанні замків та сигналів, щоб забезпечити безпеку черги, не блокуючи інший потік на тривалий час.
Ерік Ліпперт

@Eric: Чи не така абстракція вже пропонується TPL Dataflow ?
Аллон Гуралнек

52

Нитки є основним складовим елементом для певних речей (а саме паралелізму та асинхронності), і тому їх не слід відбирати. Однак для більшості людей та випадків більшості випадків є більш підходящі речі, про які ви згадали, як, наприклад, пулові нитки (які забезпечують приємний спосіб роботи з багатьма невеликими роботами паралельно без перевантаження машини, нерестуючи 2000 ниток одразу), BackgroundWorker( який інкапсулює корисні події для одного твору, який пройшов короткий короткий час).

Але тільки тому, що в багатьох випадках це більш доречно, оскільки вони захищають програміста від непотрібного вигадування колеса, дурних помилок тощо, це не означає, що клас Thread є застарілим. Він досі використовується абстракціями, названими вище, і вам все одно знадобиться, якщо вам потрібен тонкозернистий контроль над нитками, які не охоплені більш спеціальними класами.

У подібному руслі .NETне забороняється використовувати масиви, незважаючи на List<T>те , що вони краще підходять для багатьох випадків, коли люди використовують масиви. Просто тому, що ви, можливо, все ще хочете будувати речі, які не охоплені стандартною лібкою.


6
Тільки тому, що автоматична коробка передач працює 99% часу, не означає, що в ручній коробці передач немає значення, навіть ігноруючи перевагу водія.
Гуванте

4
Не дуже знайомий з ідіомами водіння, враховуючи, що я велосипедист та користувач громадського транспорту. Але ручна коробка передач не в основі автоматичної - це не механічна рука, що рухає палицею. Це насправді не абстракція над іншою, наскільки я це бачу.
Джої

2
Ви можете замінити слово "нитка" на "некерований код" у другому абзаці, і воно все одно буде дзвонити істинно
Конрад Фрікс

1
@Joey: О, я думав, ти маєш на увазі старість застарілості, цінність того, щоб мати тонкозернистий контроль, ціною зручності використання, хоча більшість ніколи цього не потребуватиме. BTW технічно цікавою частиною механічної трансмісії є зчеплення все одно.
Гуванте

3
Якщо ви , хлопці , дійсно хочуть йти з метафорою передачі, більшість послідовних передач (наприклад, передачею SMG БМВ) є , по суті, механічною коробкою передач з комп'ютером Зчеплення і важелем перемикання передач. Вони не є планетарними редукторними системами, як звичайна автоматика.
Адам Робінсон

13

Taskі Threadє різними абстракціями. Якщо ви хочете моделювати нитку, Threadклас все ще є найбільш підходящим вибором. Наприклад, якщо вам потрібно взаємодіяти з поточним потоком, я не бачу кращих типів для цього.

Однак, як ви зазначаєте, .NET додав декілька виділених абстракцій, переважних Threadу багатьох випадках.


9

ThreadКлас чи не застарів, він по - , як і раніше корисно при особливих обставинах.

Де я працюю, ми написали «фоновий процесор» як частину системи управління вмістом: сервіс Windows, який відстежує каталоги, електронні адреси та RSS-канали, і кожен раз, коли з’являється щось нове, виконує завдання - зазвичай імпортувати дані.

Спроби використовувати пул потоків для цього не спрацювали: він намагається одночасно виконати занадто багато матеріалів та виправити диски, тому ми реалізували власну систему опитування та виконання, використовуючи безпосередньо Threadклас.


Я не маю уявлення, чи правильно використовувати Thread тут - це правильне рішення, але +1 для того, щоб насправді дати приклад, де потрібно було перейти до теми.
Відмінні думки

6

Нові параметри роблять пряме використання та управління (дорогими) потоками рідше.

люди, які стикаються із завданням, яке передбачає якесь паралельне виконання, переходять безпосередньо до старого хорошого класу Thread.

Це дуже дорогий і відносно складний спосіб робити речі паралельно.

Зауважте, що витрата має найбільше значення: ви не можете використовувати повну нитку для невеликої роботи, це було б контрпродуктивно. ThreadPool поєднує витрати, клас Task - складності (винятки, очікування та скасування).


5

Щоб відповісти на запитання " чи є випадки, коли потрібно або корисно використовувати звичайний об'єкт " Old Thread ", я б сказав, що звичайна стара тема є корисною (але не потрібною), коли у вас є тривалий запущений процес, який ви виграли" t коли-небудь взаємодіяти з іншої теми.

Наприклад, якщо ви пишете програму, яка підписується на отримання повідомлень з якоїсь черги повідомлень, і ви програму буде робити більше, ніж просто обробляти ці повідомлення, тоді було б корисно використовувати Thread, оскільки нитка буде автономна (тобто ви не чекаєте, коли це закінчиться), і це недовго. Використання класу ThreadPool - це більше для того, щоб встановити в чергу купу короткочасних робочих предметів і дозволити класу ThreadPool ефективно керувати обробкою кожного з них, коли є доступна нова тема. Завдання можна використовувати там, де ви б використовували Thread безпосередньо, але у вищенаведеному сценарії я не думаю, що вони купували б вам багато. Вони допомагають вам легше взаємодіяти з потоком (що вищезгаданий сценарій не робить "


Я погоджуюся, що більшість крутих речей паралелізму розроблені навколо короткотермінових дрібнозернистих завдань, і довгі потокові нитки все ж повинні бути реалізовані System.IO.Threading.Thread.
Бен

4

Напевно, не відповідь, яку ви очікували, але я використовую Thread весь час, коли кодую проти .NET Micro Framework. MF досить скорочений і не включає абстракції вищого рівня, і клас Thread є надзвичайно гнучким, коли вам потрібно отримати останній біт продуктивності з процесора низького МГц.


Гей, це насправді досить хороший приклад! Дякую. Я не думав про рамки, які не підтримують нові функції.
Тудор

3

Ви можете порівняти клас "Нитка" з ADO.NET. Це не рекомендований інструмент для виконання роботи, але його не застаріло. Інші інструменти побудовані на ньому, щоб полегшити роботу.

Неправильно використовувати клас Thread над іншими речами, особливо якщо ці речі не забезпечують потрібну вам функціональність.


3

Це неодмінно застаріло.

Проблема з багатопотоковими програмами полягає в тому, що вони дуже важко виправитись (часто важливо недетерміновану поведінку, вхід, вихід, а також внутрішній стан), тому програміст повинен підштовхнути якомога більше роботи до рамки / інструментів. Абстрагуйте його подалі. Але, смертельним ворогом абстракції є продуктивність.

Отже, моє запитання: чи є випадки, коли потрібно або корисно використовувати звичайний об’єкт "Стара нитка" замість однієї з вищезазначених конструкцій?

Я б пішов з теми і блокуваннями тільки в тому випадку, якщо будуть серйозні проблеми з продуктивністю, високі цілі.


3

Я завжди використовував клас Thread, коли мені потрібно постійно рахувати та контролювати потоки, які я закрутив. Я усвідомлюю, що міг би скористатися ниткою для проведення всіх своїх видатних робіт, але я ніколи не знайшов хорошого способу відстежити, скільки роботи зараз виконується чи який статус.

Натомість я створюю колекцію і розміщую в них нитки після того, як я їх розкручую - саме останнє, що нитка робить, - це видалити себе з колекції. Таким чином, я завжди можу сказати, скільки потоків працює, і я можу використовувати колекцію, щоб запитати кожного, що це робить. Якщо є випадок, коли мені потрібно вбити їх усіх, зазвичай, вам доведеться встановити якийсь прапор "Abort" у вашій програмі, зачекайте, коли кожен потік помітить, що він сам і самозавершиться - у моєму випадку я може ходити по колекції і видавати Thread.Abort кожному по черзі.

У цьому випадку я не знайшов кращого способу роботи безпосередньо з класом Thread. Як зазначав Ерік Ліпперт, інші - це просто абстракції вищого рівня, і доцільно працювати з класами нижчого рівня, коли наявні версії високого рівня не відповідають вашим потребам. Так само, як іноді потрібно робити виклики Win32 API, коли .NET не відповідає вашим точним потребам, завжди знайдуться випадки, коли клас Thread є найкращим вибором, незважаючи на останні "досягнення".

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.