我有一个主要是IO绑定的连续任务(后台拼写检查器与拼写检查服务器通信).有时,此任务需要暂停并稍后恢复,具体取决于用户活动.
虽然暂停/恢复基本上是什么async/await,但我发现很少有关于如何为异步方法实现实际暂停/播放逻辑的信息.有推荐的模式吗?
我也考虑过使用Stephen Toub AsyncManualResetEvent,但认为这可能是一种矫枉过正.
Sometimes, once I have requested the cancellation of a pending task with CancellationTokenSource.Cancel, I need to make sure the task has properly reached the cancelled state, before I can continue. Most often I face this situation when the app is terminating and I want to cancel all pending task gracefully. However, it can also be a requirement of the UI workflow specification, when the new background process can only start if the current pending one has been fully …
看来我可以在同一个WCF合同接口API的以下三个不同版本之间自由切换,而不会破坏客户端:
[ServiceContract]
interface IService
{
// Either synchronous
// [OperationContract]
// int SomeMethod(int arg);
// Or TAP
[OperationContract]
Task<int> SomeMethodAsync(int arg);
// Or APM
// [OperationContract(AsyncPattern = true)]
// IAsyncResult BeginSomeMethod(int arg, AsyncCallback callback, object state);
// int EndSomeMethod(IAsyncResult ar);
}
Run Code Online (Sandbox Code Playgroud)
现有的测试客户端应用程序无需重新编译或触摸即可继续工作.如果我重新编译服务并将其引用重新导入客户端应用程序,则WSDL定义保持不变,1:1.
我的问题:
我们的想法是将一组同步SomeMethod方法转换为TAP SomeMethodAsync风格的方法,以便async/await在其实现中使用,从而提高WCF服务的可扩展性,而不会破坏现有客户端.
此外,已知在.NET 3.5和.NET 4.0下WCF服务扩展的问题.它们记录在MSKB文章"WCF服务可能在负载下缓慢扩展"和CodeProject文章"调整WCF以构建高度可伸缩的异步REST API"中.基本上,将服务契约API实现为自然异步是不够的,WCF运行时仍然阻塞了请求线程.
如果我需要推迟代码执行,直到UI线程消息循环的未来迭代之后,我可以这样做:
await Task.Factory.StartNew(
() => {
MessageBox.Show("Hello!");
},
CancellationToken.None,
TaskCreationOptions.None,
TaskScheduler.FromCurrentSynchronizationContext());
Run Code Online (Sandbox Code Playgroud)
这将类似于await Task.Yield(); MessageBox.Show("Hello!");,除了我有一个选项可以取消任务,如果我想.
在使用默认同步上下文的情况下,我可以类似地使用await Task.Run继续池线程.
事实上,我喜欢Task.Factory.StartNew和Task.Run更多Task.Yield,因为他们都明确定义了延续代码的范围.
那么,在什么情况下await Task.Yield()实际上有用呢?
我认为关于async/await的一点是,当任务完成时,继续在调用await时在相同的上下文上运行,在我的情况下,这将是UI线程.
例如:
Debug.WriteLine("2: Thread ID: " + Thread.CurrentThread.ManagedThreadId);
await fs.ReadAsync(data, 0, (int)fs.Length);
Debug.WriteLine("3: Thread ID: " + Thread.CurrentThread.ManagedThreadId);
Run Code Online (Sandbox Code Playgroud)
我不指望这个:
2: Thread ID: 10
3: Thread ID: 11
Run Code Online (Sandbox Code Playgroud)
是什么赋予了?为什么延续的线程ID与UI线程不同?
根据这篇文章 [^]我需要显式调用ConfigureAwait来改变连续上下文的行为!
这会有点长,所以请耐心等待.
我在想默认任务scheduler(ThreadPoolTaskScheduler)的行为与默认的" ThreadPool" SynchronizationContext(后者可以通过await或显式地通过隐式引用)非常相似TaskScheduler.FromCurrentSynchronizationContext().它们都安排在随机ThreadPool线程上执行的任务.实际上,SynchronizationContext.Post只是打电话ThreadPool.QueueUserWorkItem.
但是,TaskCompletionSource.SetResult当从默认排队的任务中使用时,工作方式有一个微妙但重要的区别SynchronizationContext.这是一个简单的控制台应用程序说明它:
using System;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleTcs
{
class Program
{
static async Task TcsTest(TaskScheduler taskScheduler)
{
var tcs = new TaskCompletionSource<bool>();
var task = Task.Factory.StartNew(() =>
{
Thread.Sleep(1000);
Console.WriteLine("before tcs.SetResult, thread: " + Thread.CurrentThread.ManagedThreadId);
tcs.SetResult(true);
Console.WriteLine("after tcs.SetResult, thread: " + Thread.CurrentThread.ManagedThreadId);
Thread.Sleep(2000);
},
CancellationToken.None,
TaskCreationOptions.None,
taskScheduler);
Console.WriteLine("before await tcs.Task, thread: " + Thread.CurrentThread.ManagedThreadId);
await tcs.Task.ConfigureAwait(true); …Run Code Online (Sandbox Code Playgroud) 我已经升级到 Electron 14,重构了我的项目以适应“已删除:远程模块”重大更改,但由于以下 TypeScript 错误,我无法编译它:
Type '{ plugins: true; nodeIntegration: true; contextIsolation: false; enableRemoteModule: true; backgroundThrottling: false; webSecurity: false; }' is not assignable to type 'WebPreferences'.
Object literal may only specify known properties, and 'enableRemoteModule' does not exist in type 'WebPreferences'.ts(2322)
electron.d.ts(12612, 5): The expected type comes from property 'webPreferences' which is declared here on type 'BrowserWindowConstructorOptions'
Run Code Online (Sandbox Code Playgroud)
受影响的代码:
const window = new electron.BrowserWindow({
// ...
webPreferences: {
plugins: true,
nodeIntegration: true,
contextIsolation: false,
enableRemoteModule: true,
backgroundThrottling: false,
webSecurity: …Run Code Online (Sandbox Code Playgroud) 阅读太久了.使用Task.ConfigureAwait(continueOnCapturedContext: false)可能会引入冗余线程切换.我正在寻找一致的解决方案.
长版.隐藏的主要设计目标ConfigureAwait(false)是在可能的情况下减少冗余的SynchronizationContext.Post延续回调await.这通常意味着更少的线程切换和更少的UI线程工作.但是,它并不总是如何运作.
例如,有一个实现SomeAsyncApiAPI的第三方库.请注意ConfigureAwait(false),由于某些原因,此库中的任何位置都不使用:
// some library, SomeClass class
public static async Task<int> SomeAsyncApi()
{
TaskExt.Log("X1");
// await Task.Delay(1000) without ConfigureAwait(false);
// WithCompletionLog only shows the actual Task.Delay completion thread
// and doesn't change the awaiter behavior
await Task.Delay(1000).WithCompletionLog(step: "X1.5");
TaskExt.Log("X2");
return 42;
}
// logging helpers
public static partial class TaskExt
{
public static void Log(string step)
{
Debug.WriteLine(new { step, thread = Environment.CurrentManagedThreadId }); …Run Code Online (Sandbox Code Playgroud) 此代码抛出异常.是否可以定义将捕获它的应用程序全局处理程序?
string x = await DoSomethingAsync();
Run Code Online (Sandbox Code Playgroud)
使用.net 4.5/WPF
通常我不会回答问题,但这次我想引起一些我认为可能是一个模糊而又常见的问题的注意.它是由这个问题引发的,从那以后我查看了我自己的旧代码,发现其中一些也受此影响.
下面的代码开始,等待着两个任务,task1并且task2,这几乎是相同的.task1只是task2因为它运行一个永无止境的循环.对于执行CPU限制工作的一些现实场景,这两种情况都非常典型.
using System;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApplication
{
public class Program
{
static async Task TestAsync()
{
var ct = new CancellationTokenSource(millisecondsDelay: 1000);
var token = ct.Token;
// start task1
var task1 = Task.Run(() =>
{
for (var i = 0; ; i++)
{
Thread.Sleep(i); // simulate work item #i
token.ThrowIfCancellationRequested();
}
});
// start task2
var task2 = Task.Run(() =>
{
for (var i = 0; …Run Code Online (Sandbox Code Playgroud)