2012-04-13 2 views
1

Я хочу сделать result (возвращаемый результат тяжелого процесса) доступным после выполнения Heavy Process в дополнительном потоке, поскольку в основном ожидается, что во время процесса пользовательский интерфейс не будет работать, После процесс осуществляется может играть с resultвозвращение результата из дополнительной темы

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

это образец, который я хочу иметь дело с наилучшим подходом:

 public ACollection DoProcess(Document docProcess) 
     { 
      ACollection result = new ACollection(); 

      ThreadStart threadStart = delegate 
      { 
       result = MyProcess(docProcess); 
      }; 
      var threadProcess = new Thread(threadStart); 
      threadProcess.Start();  

      return result ; 
} 

Другие возможные подходы могут быть IAsyncResult, BackgroundWorker, использование таймеров и проверки состояния, вместо возвращения результата в способ справиться с этим и сообщить об этом в пользовательском интерфейсе отправить его непосредственно в поточно-образом для наших элементов управления пользовательского интерфейса ...

Пожалуйста, дайте свое собственное мнение и образец в подобном случае, заранее спасибо

Edit 3: подход - на основе Ответ Брайана

 LenzCollection myResultCollection = new LenzCollection();  

     TaskScheduler ui = TaskScheduler.FromCurrentSynchronizationContext(); 

     Task.Factory.StartNew(() => 
      { 
       myResultCollection = DoCollect(docProcess); 
       //Task.WaitAll(); 

       return myResultCollection; 
      }).ContinueWith((task => 
      { 
       myResultCollection = task.Result; 
      }), ui); 

     return myResultCollection; 

Он по-прежнему не ждать и не даст желаемого результата

+1

'while (threadProcess.IsAlive) {}' делает эту однопоточную. И CPU-hog. –

+0

Я получил несколько минут спустя и отредактировал, спасибо, но все же должен знать ваш предлагаемый многоразовый подход, thx – LastBye

+1

BackgroundWorker уже получил всю функциональность, о которой вы просили. Так зачем пытаться изобрести колесо? – Zarat

ответ

1

Вариант № 1:

Используйте Task класс и метод ContinueWith.

TaskScheduler ui = TaskScheduler.FromCurrentSynchronizationContext(); 

Task.Factory.StartNew(() => 
    { 
    var result = MyProcess(docProcess); 
    return result.ToString(); 
    }).ContinueWith((task => 
    { 
    textBox1.Text = task.Result; 
    }, ui); 

Вы должны помнить, чтобы пройти в правильном контексте синхронизации в метод ContinueWith. Вы можете видеть, как я это сделал с переменной ui.

Вариант № 2:

Используйте новые async и await ключевые слова.

private async void SomeButton_Click(object sender, EventArgs args) 
{ 
    textBox1.Text = await Task.Run(() => 
    { 
     var result = MyProcess(docProcess); 
     return result.ToString(); 
    }); 
} 

Очевидно, что это намного легче на глазах и делает все маршалингом и синхронизации контекста вещи для вас.


новые ключевые слова будут доступны в C# 5.0, но вы можете использовать их теперь через Async CTP. CTP использует TaskEx вместо Task.

+0

Это еще один умный ответ здесь, Мне это нравится, это не проблема, даже лучше для меня, если она основана на C# 5.0, которая может быть применима в настоящее время любым способом, спасибо за сообщение, я вернусь через несколько минут, протестирую его и расскажу вам об этом, если потребуется , +1 благодарю вас за участие ated inv :) – LastBye

+0

Я протестировал оба метода до того, как я разместил их, чтобы они работали. Просто помните, если вы используете второй метод с помощью Async CTP, который вам нужно использовать 'TaskEx.Run' вместо' Task.Run'. Это всего лишь вещь CTP. –

+0

Да, я вижу, я хочу адаптировать себя и свой код вместе с ним и спросить вас, если это необходимо :) – LastBye

2

Просто реализовать событие, которое вы регистрируетесь перед выполнением метода. И пусть метод поднимет событие, когда закончится.

Для примера:

public delegate void MyEventHandler(string result); 
public class MyClass 
{ 
    public event MyEventHandler MyEvent; 
    private void Event(string result) 
    { 
    MyEventHandler handler = MyEvent; 
    if(handler != null) 
     handler(result); 
    } 

    public void DoSomethingLong() 
    { 
    //Do something 
    Event("Finish"); 
    } 
} 

Теперь вы можете запустить этот как

MyClass.Event += MyEventHandler(On_Event); 
Thread t = new Thread(MyClass.DoSomethingLong); 
t.Start();  

void On_Event(string result) 
{ 
    //Get executed when finished; 
} 

пример для вызова к UI Thread

void On_Event(string result) 
{ 
    if(this.InvokeRequired) 
    { 
    MyEventHandler handler = new MyEventHandler(On_Event); 
    Invoke(handler, new object[] { result }); 
    return; 
    } 
    // At this point you can access your UI without having Cross-Threaded operation! 
} 
+0

просьба указать кусок предлагаемого кода в этой ситуации – LastBye

+1

недостаточно кода? – RaphaelH

+0

Я проверю его и подумаю, что это может быть многоразовый фрагмент кода. Как и в целом, действительно спасибо, есть ли у него какие-то недостатки? как вы сравниваете его с BackgroundWorker? – LastBye

1

Если вы используете .NET Framework 4.0 or +, вы можете запустить процесс из другого потока и процесса в Task.ContinueWith, например

Process pro = null; 
Task.Factory.StartNew(() => { 
    pro =new Process(..); 
    pro.Start(); 
    pro.WaitForExit(); 
}).ContinueWith(..process data recieved from the pro) 

EDIT

Не используйте while(...), но использовать pro.WaitForExit()

Надеются, что это помогает.

+0

Это лучший подход в этом случае? Я не был знаком с этим и думал, что это может быть полезно. Для использования этого приведенный код можно использовать в моем примере? – LastBye

+1

@Sypress: Является ли это * лучшим * или не должен принимать решение * вы * :) Это современный подход и самый компактный, в данном случае. Не нужно объявлять события, обрабатывать их или определять BackgroundWorker. Я предлагаю вам попробовать (скопировать/вставить), чтобы узнать, соответствует ли он вашим потребностям. – Tigran

+0

Я вижу, может быть, глупо, но это действительно известно, и я не мог принести/преобразовать свой код в него: D, если «pro» - это тяжелый процесс, о котором я упоминал выше, где мой экземпляр «результат», я знаю, что это должно быть просто для вы, но можете ли вы, пожалуйста, предоставить мне свои экземпляры и облегчить мне перемещение моего кода на основе этого, действительно спасибо за этот современный подход;) – LastBye

2

В приложении для рабочего стола (WinForms/WPF) лучшим и простым подходом является BackgroundWorker. Он был разработан, чтобы справиться с этим.

+0

Во многих статьях я видел, что это рекомендуется в большинстве подобных проблем, но вы знаете, что я хочу иметь больше полномочий в том, как я использую свои модули, таким образом я должен присоединиться к отдельной части кода и изменить форму модуля/структура кода, если это будет необходимость, и никакие фрагменты кода не могут помешать ему, так что я буду делать, в любом случае будет рад и оценен, если какой-либо предлагаемый пример кода, который вы могли бы дать в моей ситуации. – LastBye

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