我想在后台线程中执行一些代码,并让后台代码定期在主线程上执行代码。如下所示:
void functionThatMustBeRunOnMainThread(string arg) {
Debug.Print("On main thread: "+arg);
}
// Run the task asynchronously. On completion, call completionAction in the main thread.
void launchAsyncBackgroundTask( Action<bool> completionAction ) {
performInArbitraryBackgroundThread(() => {
// do first long running thing
sleep(10);
// notify main thread
performOnMainThread(() => {
functionThatMustBeRunOnMainThread("phase 1");
});
// do second long running thing
sleep(10);
// notify main thread
performOnMainThread(() => {
functionThatMustBeRunOnMainThread("phase 2");
});
// do final long running thing
sleep(10);
performOnMainThread(() => {
Debug.Print("Done!");
completionAction(true);
});
});
}
我知道BackgroundWorker
,但它并没有提供我所寻求的灵活性。
这里有两点 -
使用Grand Central Dispatch在Obj-C中做这件事是微不足道的(它几乎如上所述)。是否有C#等价物?
答案 0 :(得分:4)
您可以使用async-await
以及Task Parallel Library
轻松实现您的需求:
此示例假定您的MethodThatDoesStuffInBackground
或任何其他耗时的方法都是CPU绑定操作。如果没有,他们正在做IO,你可以放弃使用Task.Run
:
(应该从UI线程调用此方法才能正常工作)
public async Task DoStuff()
{
await Task.Run(() => MethodThatDoesStuffInBackground());
FunctionThatMustRunOnMainThread();
await Task.Run(() => MethodThatDoesMoreStuffInBackground());
FunctionThatMustRunOnMainThread();
await Task.Run(() => EvenMoreWorkInBackgroundThread());
FunctionThatMustRunOnMainThread();
}
答案 1 :(得分:1)
我建议将Task.Run
用于后台工作,IProgress<T>
用于进度更新,Task
用于完成通知。这种方法使您可以将背景逻辑保留在一个位置,与UI分开。
这样的事情:
// Run the task asynchronously. On completion, call completionAction in the main thread.
async Task launchBackgroundTaskAsync( Action<bool> completionAction ) {
var progress = new Progress<string>(arg => {
Debug.Print("On main thread: "+arg);
};
await Task.Run(() => BackgroundLogic(progress));
completionAction(true);
}
void BackgroundLogic(IProgress<string> progress) {
// do first long running thing
sleep(10);
// notify main thread
if (progress != null)
progress.Report("phase 1");
// do second long running thing
sleep(10);
// notify main thread
if (progress != null)
progress.Report("phase 2");
// do final long running thing
sleep(10);
if (progress != null)
progress.Report("Done!");
}
请注意,不再需要completionAction
,因为launchBackgroundTaskAsync
本身会返回Task
。它可以简单地删除而不会丢失任何功能 - 只需让此方法的调用者使用await
:
async Task launchBackgroundTaskAsync() {
var progress = new Progress<string>(arg => {
Debug.Print("On main thread: "+arg);
};
await Task.Run(() => BackgroundLogic(progress));
}