2016-02-09 2 views
2

Я пытаюсь выполнить параллельные методы, , но форма застревает всякий раз, когда Я называю их.Windows Form застрял в нескольких задачах async

Пожалуйста, исправьте, что я делаю неправильно. Вот код:

public partial class Form1 : Form 
{ 
    private async void button1_Click(object sender, EventArgs e) 
    { 
     var itemList = new List<string>() { "Field1", "Field2", "Field3" }; 

     await Task.WhenAll(itemList.Select(item => 
      new WorkToDo(item).StartWork() 
      )); 
    } 
} 

public class WorkToDo 
{ 
    private string id; 

    public WorkToDo(string id) 
    { 
     this.id = id; 
    } 

    public async Task<bool> StartWork() 
    { 
     Calculate(); 
     Analyze(); 
     SomeToDo(); 
     var result = Save(); 
     await Task.Delay(100); 
     return result; 
    } 

    private bool Calculate() 
    { 
     //Some complex and time taking calculation will be here 
     return true; 
    } 

    private bool Analyze() 
    { 
     //Some complex and time taking calculation will be here 
     return true; 
    } 

    private bool SomeToDo() 
    { 
     //Some complex and time taking calculation will be here 
     return true; 
    } 

    private bool Save() 
    { 
     //Some complex and time taking calculation will be here 
     return true; 
    } 
} 
+1

См. [«Если вопросы включают« теги »в их названиях?»] (Http://meta.stackexchange.com/questions/19190/should-questions-include-tags-in-their-titles), где консенсус «нет, они не должны»! –

ответ

3

Вы должны помнить, что нормальная асинхронная/ОЖИДАНИЕ по-прежнему будет выполняться в потоке пользовательского интерфейса.

Так, чтобы быть уверенным, что реальное действие долго нажимается на фоне потока, вам нужно обернуть его в Task.Run ... как Task.Run(() => Task.WhenAll(tasks));

Чтобы завершить этот вопрос немного больше (видя другой ответ доступно), Task.Run использование не является чем-то, что можно сделать легкомысленно. Все зависит от того, какой код нужно обернуть. Существует хорошая запись серии на этом блоге Стивена Клири здесь http://blog.stephencleary.com/2013/11/taskrun-etiquette-examples-even-in.html, поэтому найдите время, чтобы пройти через это и посмотреть, что подходит вашему проекту.

Или смотрите здесь для некоторых других деталей от Стивена https://stackoverflow.com/a/18015586

+0

Да, теперь он работает. можете ли вы объяснить о Task.Run()? Этот код хорош для длительных операций? Спасибо –

+4

Основная причина для Task.Run действительно для «как я могу запустить операцию в фоновом потоке так, как это ожидаемо» – Depechie

0

ИМХО, если вы используете Async операции вам не нужно Task.Run(), если у вас есть Sync Task и сделать это асинхронно вам нужно Task.Run()

If вы используете обычный синхронный процесс, просто возвращаете Task<T> и используйте это Task.Run(()), чтобы использовать фоновый поток для обработки. См this answer

private async void button1_Click(object sender, EventArgs e) 
{ 
    var itemList = new List<string>() { "Field1", "Field2", "Field3" }; // more than 50 items 

    Task.Run(() => Task.WhenAll(tasks)); 
} 


public class WorkToDo 
{ 
private string id; 

public WorkToDo(string id) 
{ 
    this.id = id; 
} 

public async Task<bool> StartWork() 
{ 
    var t1 = Calculate(); 
    var t2 = Analyze(); 
    var t3 = SomeToDo(); 

    //Assuming you need to do all this before you save 
    // so wait for the all. 

    await Task.WhenAll(t1,t2,t3); 
    var result = await Save(); 
    return result; 
} 

private async Task<bool> Calculate() 
{ 
    //Some complex and time taking calculation will be here 
    //Assuming here you have some DoAsync() method 
    return true; 
} 

private async Task<bool> Analyze() 
{ 
    //Some complex and time taking calculation will be here 
    return true; 
} 

private async Task<bool> SomeToDo() 
{ 
    //Some complex and time taking calculation will be here 
    return true; 
} 

private async Task<bool> Save() 
{ 
    //Some complex and time taking calculation will be here 
    return true; 
} 

Использование WhenAll() имеет некоторое преимущество, как распространяющиеся все ошибки сразу, см this

+1

Не сказать, что вы ошибаетесь, все зависит от того, какой тип вызова используется. Существует хорошая запись на эту тему, сделанную здесь http://blog.stephencleary.com/2013/11/taskrun-etiquette-examples-even-in.html, не зная фактического кода проекта, он угадывает, что было бы лучше использовать. – Depechie

+0

@Depechie Спасибо, я лучше понимаю из блога stephancleary. – Eldho

1

Проблема, что у вас есть, что StartWorkпретензии быть асинхронными, и все же это не , Он выполняет всю свою работу синхронно.

Опознавательный метод async не делает его асинхронным. он просто позволяет вам использовать ключевое слово await из этого метода. Если вы выполняете длительные синхронные операции с помощью метода async, этот метод все равно будет выполнять эту работу синхронно.

Здесь есть два подхода. Если в StartWork есть некоторые вещи, которые по сути являются асинхронными, вам нужно обернуть любую работу синхронного процессора, которую вы имеете при вызовах Task.Run, чтобы синхронная работа, которую вы можете выполнить асинхронно, в потоке пула потоков ,

Если нет асинхронных операций по умолчанию, вы должны сделать в StartWork, тогда сделать метод четко синхронным. Попросите его вернуть логическое значение, а не Task, и отрегулируйте имя, чтобы отразить тот факт, что он синхронный. Затем попросите вызывающего абонента, который вызывает его, использовать Task.Run, чтобы выполнить эту операцию в потоке потока потока асинхронно.

Имея StartWorkложно утверждает быть асинхронными, а потом еще с помощью Task.Run сделать якобы асинхронной работы в другом потоке будет чрезвычайно запутанными другими читателями вашего кода, так как не должна быть никаких оснований выгрузите асинхронный метод в поток, отличный от UI.

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