如何在 C# 中切换主线程和后台线程?
How can I switch between main and background thread in C#?
我想在后台线程中执行一些代码,并让后台代码定期在主线程中执行代码。类似于以下内容:
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
,但它没有提供我正在寻找的灵活性。
这里有两点 -
- 我 'calling back' 多次到主线程 - 在执行期间两次,然后第三次执行用户提供的完成回调。
- 代码可读性很强。即使涉及两个线程,同步也是隐含的或在别处处理 - 如果仅从理想化的角度来看,从上到下阅读事件序列是清楚的。没有静态函数或额外的 类 可以覆盖 - 这一切都与 lambda expressions/closures.
内联
在 Obj-C 中使用 Grand Central Dispatch 很容易做到这一点(它的工作原理和上面的差不多)。是否有 C# 等效项?
您可以使用 async-await
along with the 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();
}
我建议使用 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
本身 returns 一个 Task
。它可以简单地删除而不会损失任何功能 - 只需让此方法的 callers 使用 await
:
async Task launchBackgroundTaskAsync() {
var progress = new Progress<string>(arg => {
Debug.Print("On main thread: "+arg);
};
await Task.Run(() => BackgroundLogic(progress));
}
我想在后台线程中执行一些代码,并让后台代码定期在主线程中执行代码。类似于以下内容:
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
,但它没有提供我正在寻找的灵活性。
这里有两点 -
- 我 'calling back' 多次到主线程 - 在执行期间两次,然后第三次执行用户提供的完成回调。
- 代码可读性很强。即使涉及两个线程,同步也是隐含的或在别处处理 - 如果仅从理想化的角度来看,从上到下阅读事件序列是清楚的。没有静态函数或额外的 类 可以覆盖 - 这一切都与 lambda expressions/closures. 内联
在 Obj-C 中使用 Grand Central Dispatch 很容易做到这一点(它的工作原理和上面的差不多)。是否有 C# 等效项?
您可以使用 async-await
along with the 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();
}
我建议使用 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
本身 returns 一个 Task
。它可以简单地删除而不会损失任何功能 - 只需让此方法的 callers 使用 await
:
async Task launchBackgroundTaskAsync() {
var progress = new Progress<string>(arg => {
Debug.Print("On main thread: "+arg);
};
await Task.Run(() => BackgroundLogic(progress));
}