Яка різниця між завданням і ниткою?


378

У C # 4.0 ми маємо Taskв просторі імен System.Threading.Tasks . У чому полягає справжня різниця між Threadта Task. Я зробив декілька зразкових програм (допомогу, взяту з MSDN) заради власного навчання

Parallel.Invoke 
Parallel.For 
Parallel.ForEach 

але є багато сумнівів, оскільки ідея не така зрозуміла.

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


8
теми виконують завдання
pm100

Відповіді:


314

Завдання - це те, що ви хочете зробити.

Нитка - один із багатьох можливих працівників, який виконує це завдання.

У термінах .NET 4.0 Завдання являє собою асинхронну операцію. Нитки (и) використовуються для завершення цієї операції, розбиваючи роботу на шматки і призначаючи окремі нитки.


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

Можливі обидва сценарії: в оптимальній ситуації потоки виконують самостійну роботу без необхідності синхронізувати з іншими потоками. На практиці замки використовують для узгодження ниток.
Mitch Wheat

451

З точки зору інформатики, a Task- це майбутнє або обіцянка . (Деякі люди використовують ці два терміни синомічно, інші використовують їх по-різному; ніхто не може погодитися на точне визначення.) В основному, Task<T>"обіцяє" повернути вам T, але не зараз, дорогий, я начебто зайнятий, чому б не ви повернетесь пізніше?

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

Зокрема, Taskце НЕ сказати , чому це, що це займає так багато часу , щоб повернути значення. Це може бути , що це займає багато часу , щоб обчислити, чи це може бути , що це займає багато часу для отримання. Тільки в першому випадку ви використовували Threadб запуск а Task. (У .NET, потоки виглядають дорого, тому ви, як правило, хочете їх максимально уникати, а реально використовувати їх лише у тому випадку, якщо ви хочете виконувати декілька важких обчислень на декількох процесорах. Наприклад, у Windows тематика важить 12 KiByte ( Я думаю) в Linux нитка важить всього 4 KiByte, в Erlang / BEAM навіть всього 400 байт. У .NET, це 1 MiByte!)


29
Цікаво, що в ранніх випусках попереднього попереднього перегляду TPL (Task Parallel Library) були завдання та майбутнє <T>. Майбутнє <T> потім було перейменовано в Завдання <T>. :)
Лі Кемпбелл

23
Як ви обчислили 1 Мб для .NET?
dvallejo

5
@DanVallejo: Про це число згадували в інтерв'ю з дизайнерською командою TPL. Я не можу сказати вам, хто це сказав чи яке інтерв'ю, я дивився це роки тому.
Йорг W Міттаг

9
@RIPUNJAYTRIPATHI Звичайно, але це не потрібно, щоб це був інший потік, це може бути тема, яка вимагає роботи в першу чергу.
Кріс Пітман

7
.NET просто використовує потоки Windows у Windows, тому розмір однаковий - за замовчуванням, як правило, 1 МіБ віртуальної пам'яті для обох. Фізична пам'ять використовується за потребою в розмірах сторінок (зазвичай 64 кіБ), однакових з нативним кодом. Мінімальний розмір стека нитки залежить, наприклад, від ОС - 256 кб для Vista. У Linux x86 Linux за замовчуванням зазвичай становить 2 MiB - знову ж таки, виділяється в шматки розміру сторінки. (спрощення) Ерланг використовує лише один системний потік за процес; ці 400 байт посилаються на щось подібне до .NET Task.
Луань

39

Нитка

Речі з чистого металу, вам, мабуть, не потрібно її використовувати, можливо, ви можете скористатися LongRunningзавданням і скористатися вигодами з TPL - Паралельної бібліотеки завдань, включеної в .NET Framework 4 (лютий, 2002) і вище (також .NET Основні).

Завдання

Абстракція над нитками. Він використовує пул потоків (якщо ви не вказали завдання як LongRunningоперацію, якщо так, то нова кришка створюється під кришкою для вас).

Нитка басейну

Як випливає з назви: пул ниток. Це рамка .NET, яка обробляє обмежену кількість потоків для вас. Чому? Оскільки відкриття 100 потоків для виконання дорогих операцій з процесором на процесорі з лише 8 ядрами, безумовно, не є хорошою ідеєю. Рамка підтримуватиме цей пул для вас, повторно використовуючи потоки (не створюючи / вбиваючи їх під час кожної операції) та виконуючи деякі з них паралельно таким чином, щоб ваш процесор не записувався.

Гаразд, але коли використовувати кожен?

В резюме: завжди використовуйте завдання.

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

Але врахуйте, що:

  • Обмеження вводу-виводу : для операцій, пов'язаних з введенням-виведеннями (дзвінки до бази даних, файли читання / запису, виклики API та ін.) Уникайте звичайних завдань, використовуйте LongRunningзавдання ( або потоки, якщо потрібно ). Тому що використання завдань призведе вас до пулу потоків із зайнятими кількома потоками та безліччю інших завдань, які чекають на свою чергу, щоб взяти пул.
  • Прив’язаний до процесора : для операцій, пов'язаних з процесором, просто використовуйте звичайні завдання (для внутрішнього використання пулу потоків) і будьте раді.

невелика корекція, нитка - це не "голий метал". він реалізований ОС, більшість реалізацій ретранслюються за особливостями процесора та CS, але вони не реалізовані апаратним забезпеченням.
Томер Ш

7

Ви можете Taskвказати, що ви хочете зробити, потім додайте це Taskза допомогою Thread. так що Taskце буде виконуватися в новоспеченому, Threadа не на потоці GUI.

Використовуйте Taskз TaskFactory.StartNew(Action action). Тут ви виконуєте делегат, тому якщо ви не використовували жоден потік, він би виконувався в тому ж потоці (GUI-потоці). Якщо ви згадуєте потік, ви можете виконати це Taskв іншому потоці. Це непотрібна робота, оскільки ви можете безпосередньо виконати делегата або приєднати його до потоку та виконати його в цьому потоці. Тому не використовуйте його. це просто непотрібно. Якщо ви маєте намір оптимізувати своє програмне забезпечення, це хороший кандидат, який слід усунути.

** Зверніть увагу, що Actionце a delegate.


6

На додаток до вищезазначених моментів, було б добре знати, що:

  1. Завдання за замовчуванням є фоновим завданням. Ви не можете мати завдання переднього плану. З іншого боку, нитка може бути фоновою чи передньою формою (Використовуйте властивість IsBackground, щоб змінити поведінку).
  2. Завдання, створені в пулі ниток, переробляють нитки, що допомагає заощадити ресурси. Тому в більшості випадків завдання повинні бути вашим вибором за замовчуванням.
  3. Якщо операції швидкі, набагато краще використовувати завдання замість нитки. Для тривалих операцій завдання не дають великих переваг перед потоками.

4

Зазвичай я використовую Taskдля взаємодії з Winforms і простим фоновим працівником, щоб він не замерзав інтерфейс користувача. ось приклад, коли я вважаю за краще використовуватиTask

private async void buttonDownload_Click(object sender, EventArgs e)
{
    buttonDownload.Enabled = false;
    await Task.Run(() => {
        using (var client = new WebClient())
        {
            client.DownloadFile("http://example.com/file.mpeg", "file.mpeg");
        }
    })
    buttonDownload.Enabled = true;
}

VS

private void buttonDownload_Click(object sender, EventArgs e)
{
    buttonDownload.Enabled = false;
    Thread t = new Thread(() =>
    {
        using (var client = new WebClient())
        {
            client.DownloadFile("http://example.com/file.mpeg", "file.mpeg");
        }
        this.Invoke((MethodInvoker)delegate()
        {
            buttonDownload.Enabled = true;
        });
    });
    t.IsBackground = true;
    t.Start();
}

різниця в тому, що вам не потрібно використовувати MethodInvokerі скорочувати код.


4

Завдання - це як операція, яку ви хочете виконати, Thread допомагає керувати цими операціями через декілька технологічних вузлів. завдання - це легкий варіант, оскільки Threading може призвести до складного управління кодом,
я пропоную завжди читати з MSDN (найкращого у світі)

Завдання

Нитка


3

Завдання може розглядатися як зручний і простий спосіб виконати щось асинхронно і паралельно.

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

Ви можете виконати те саме за допомогою нитки (з великим зусиллям), як і з завданням.

Нитка

int result = 0;
Thread thread = new System.Threading.Thread(() => { 
    result = 1; 
});
thread.Start();
thread.Join();
Console.WriteLine(result); //is 1

Завдання

int result = await Task.Run(() => {
    return 1; 
});
Console.WriteLine(result); //is 1

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

Як вказує ця стаття , завдання передбачає наступні потужні функції над потоком.

  • Завдання налаштовані на використання багатоядерних процесорів.

  • Якщо система має кілька завдань, то вона використовує внутрішньо пул CLR потоків, і тому не має накладних витрат, пов'язаних зі створенням виділеного потоку за допомогою потоку. Також зменшіть час переключення контексту між декількома потоками.

  • Завдання може повернути результат. Не існує прямого механізму повернення результату з потоку.
  • Зачекайте на наборі завдань, без сигнальної конструкції.

  • Ми можемо ланцюжок завдань разом виконувати одне за одним.

  • Встановіть стосунки батько / дитина, коли одне завдання починається з іншого завдання.

  • Виняток дочірньої задачі може поширюватися на батьківське завдання.

  • Скасування підтримки для завдання через використання маркерів для скасування.

  • Асинхронна реалізація проста у виконанні завдань, використовуючи ключові слова "async" та "очікувати".

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