2016-03-20 2 views
2

Я попытаюсь проиллюстрировать свой вопрос бессмысленным примером, который вы видите ниже.Является ли async-await необходимым условием для параллельной работы двух независимых задач в моей программе?

using System; 
using System.IO; 
namespace PointlessProgram 
{ 
    class PointlessClass 
    { 
     public static void WriteFooToTextFile () 
     { 
      using (System.IO.StreamWriter file = new System.IO.StreamWriter(@"C:\Users\Hillary\Documents\PointlessFolder\Foo.txt")) 
      { 
       file.Write("Foo"); 
      } 
     } 

     public static void WriteBarToTextFile () 
     { 
      using (System.IO.StreamWriter file = new System.IO.StreamWriter(@"C:\Users\Hillary\Documents\PointlessFolder\Bar.txt")) 
      { 
       file.Write("Bar"); 
      }  
     } 

     static void Main() 
     { 
      WriteFooToTextFile(); // (A) 
      WriteBarToTextFile(); // (B)  
     } 
    } 
} 

Здесь (B) не нужно запускать после (A), поскольку он не зависит от какой-либо продукции, производимой (A) и neighter делает (A) зависит от (B). Предположим, что у моего компьютера есть 2 процессора и он будет использовать всю свою вычислительную мощность для запуска этой программы. Будет ли компилятор выяснить, что (A) и (B) могут выполняться параллельно или они будут запускать их один за другим, если я не буду писать свой код, чтобы сообщить машине, чтобы он не дождался завершения (A) до начала выполнения (B)? И если да, то async - await, как я могу изменить это исполнение от

=== 
A 
--- 
B 
=== 

к

======== 
A | B 
======== 

???

Что я нахожу в заблуждении о async - await является то, что вы не думаете, с точкой зрения partioning вашей программы в самостоятельные задачи A, B, C ...; вы вместо этого думаете в терминах «эта задача» и «все остальное», и все, что вы делаете, говорит «все остальное может продолжать работать, пока эта задача выполняется».

Пожалуйста, помогите мне разобраться.

+2

Я не уверен, что вы просите уже не может дать ответ на поиск и чтение о асинхронном, многопоточность, TPL (Task Parallel Library) и т.д. –

+1

@KoryGill Согласен..но у кого-то, кто работает для президента, не хватает времени, чтобы это сделать;). – i3arnon

ответ

1

Как ваша программа представлена, «A» будет работать первым, а затем «B» будет работать после завершения «A». Однако вы можете реализовать модель async/await, так как мы действительно не заботимся о возвращаемых значениях, более безопасным и более кратким может быть просто запуск каждого вызова метода в новом потоке. Мы можем начать с:

static void Main() 
{ 
    Task.Run(() => WriteFooToTextFile()); // (A) 
    Task.Run(() => WriteBarToTextFile()); // (B)  
} 

(. Чтобы использовать Task объект, мы должны добавить using System.Threading.Tasks; директиву)

еще один аргумент, чтобы использовать модель задачи, является то, что модель async/awaitне многопоточное, но просто асинхронное выполнение в одном и том же потоке приложения - поэтому, чтобы лучше использовать оба процессора, вы должны выполнять отдельные потоки.

Конечно, теперь с многопоточным, мы должны осознавать потенциальное состояние гонки. Поскольку никакой зависимости между каждой задачей в вашем примере не существует, не должно быть никаких предсказуемых последствий для того, чтобы одна задача завершилась первой по сравнению с другой. Однако мы не хотим, чтобы программа заканчивалась до тех пор, пока оба потока не завершились; кроме того, мы не хотим, чтобы исключения из одного процесса мешали другому, но мы идеально хотели бы обрабатывать все исключения одновременно. Поэтому мы могли бы реализовать вызовы следующим образом:

static void Main() 
{ 
    try 
    { 
     Task.WaitAll(new Task[] { 
      Task.Run(() => WriteFooToTextFile()), // (A) 
      Task.Run(() => WriteBarToTextFile()) // (B) 
     }); 
    } 
    catch (AggregateException e) 
    { 
     // Handle exception, display failure message, etc. 
    } 
} 
5

Будет ли компилятор выяснять, что (A) и (B) могут работать параллельно?

№ компилятор автоматически не распараллеливает что-либо для вас.

И если да, то асинхронно ожидаем, как я могу изменить это исполнение?

Нет. async-wait не имеет никакого отношения к этому.

Ваш код может быть последовательным, является ли он синхронным или нет. И это может быть параллельно, является ли оно асинхронным или нет.

Например, синхронные и параллельно:

var task1 = Task.Run(() => WriteFooToTextFile()); 
var task2 = Task.Run(() => WriteBarToTextFile()); 
Task.WaitAll(task1, task2); 

и асинхронные и последовательное:

await WriteFooToTextFileAsync(); 
await WriteBarToTextFileAsync(); 

Делая свои операции действительно асинхронной вы освобождаете темы и дать им возможность работать на других частях вашего заявление. Но если нет других частей, они сидят и ждут в ThreadPool, и вы не получите многого.

2

Ваш код синхронный, поэтому выполняется A, затем выполняется B. Чтобы запустить их одновременно, вы должны использовать команду Task.Run() для выполнения их в отдельной задаче, затем await их завершение.

Итак:

public static async Task Write() 
{ 
    Task t1 = Task.Run(() => WriteFooToTextFile()); 
    Task t2 = Task.Run(() => WriteBarToTextFile()); 
    await Task.WhenAll(t1, t2); 
} 

с использованием:

await PointlessClass.Write(); 

Примечание сигнатура метода записи теперь async Task. Вам нужно будет сделать обработчик событий (или что-то другое, вызывающее этот код), также async.

Как упоминает i3arnon ниже, вам не нужно делать свой асинхронный код для выполнения параллельных операций. Обычно это делается, чтобы остановить поток пользовательского интерфейса от блокировки в приложениях WPF и WinForms, поэтому вы видите, что код идет рука об руку во многих примерах.

Если вы используете консоль, попробуйте:

static void Main() 
{ 
    MainAsync().Wait(); 
} 

static async Task MainAsync() 
{ 
    Task t1 = Task.Run(() => WriteFooToTextFile()); 
    Task t2 = Task.Run(() => WriteBarToTextFile()); 
    await Task.WhenAll(t1, t2); 
} 

См: Async Console App для получения дополнительной информации.

+1

'Main' не может быть async – i3arnon

+0

Точка входа консольного приложения не может возвращать' Task' или быть асинхронной. –

+0

Yup конечно. Я предположил (может быть, ошибочно), что это был тривиальный пример, но собирался внедряться в самостоятельный класс. –

2

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

https://en.wikipedia.org/wiki/Von_Neumann_architecture

Так как результат, вы должны явно указать, что можно безопасно работать параллельно. Компилятор должен рассматриваться как немой.

С точки зрения способов достижения параллельной задачи вы можете использовать подобные Parallel.Invoke. Я бы, наверное, просто прибегал к Parallel invoke или Task.Run в приведенном выше экземпляре кода.

Смежные вопросы