我试图用一种新的语法替换我的旧的"即发即忘"调用,希望更简单,它似乎在逃避我.这是一个例子
class Program
{
static void DoIt(string entry)
{
Console.WriteLine("Message: " + entry);
}
static async void DoIt2(string entry)
{
await Task.Yield();
Console.WriteLine("Message2: " + entry);
}
static void Main(string[] args)
{
// old way
Action<string> async = DoIt;
async.BeginInvoke("Test", ar => { async.EndInvoke(ar); ar.AsyncWaitHandle.Close(); }, null);
Console.WriteLine("old-way main thread invoker finished");
// new way
DoIt2("Test2");
Console.WriteLine("new-way main thread invoker finished");
Console.ReadLine();
}
}
Run Code Online (Sandbox Code Playgroud)
两种方法都做同样的事情,但是我似乎已经获得了(没有必要EndInvoke和关闭处理,这仍然有点争议)我正在以新的方式失去等待a Task.Yield(),这实际上带来了一个新的问题必须重写所有现有的异步F&F方法只是为了添加一个单行.在性能/清理方面是否有一些无形的收获?
如果我无法修改背景方法,我将如何应用异步?在我看来,没有直接的方法,我将不得不创建一个等待Task.Run()的包装器异步方法?
编辑:我现在看到我可能会错过一个真正的问题.问题是:给定一个同步方法A(),如何使用async/ await以一种即发即忘的方式异步调用它,而不会得到比"旧方式"更复杂的解决方案
一般的答案,如这里和这里 来发射后不管的问题是不使用异步/ AWAIT,但使用Task.Run或TaskFactory.StartNew在同步方式传递来代替.
但是,有时我想要发射并忘记的方法是异步的,并且没有等效的同步方法.
更新注释/警告:正如Stephen Cleary在下面指出的那样,在您发送响应后继续处理请求是危险的.原因是AppDomain可能会在该工作仍在进行时关闭.有关详细信息,请参阅其响应中的链接.无论如何,我只是想提前指出,所以我不会让任何人走错路.
我认为我的情况是有效的,因为实际工作是由不同的系统(不同服务器上的不同计算机)完成的,所以我只需要知道该消息已经留给该系统.如果存在异常,则服务器或用户无法对其进行任何操作并且不会影响用户,我需要做的就是参考异常日志并手动清理(或实现一些自动机制).如果关闭AppDomain,我将在远程系统中有一个残留文件,但是我将在常规维护周期中选择它,因为我的Web服务器(数据库)不再知道它的存在,并且它的名称是唯一的时间戳,它仍然会徘徊不会导致任何问题.
如果我能像Stephen Cleary所指出的那样访问持久性机制,那将是理想的,但不幸的是我现在还没有.
我认为只是假装DeleteFoo请求在客户端(javascript)已经完成,同时保持请求打开,但我需要响应中的信息继续,所以它会保持原状.
那么,原来的问题......
例如:
//External library
public async Task DeleteFooAsync();
Run Code Online (Sandbox Code Playgroud)
在我的asp.net mvc代码中,我想以一种即发即忘的方式调用DeleteFooAsync - 我不想阻止等待DeleteFooAsync完成的响应.如果DeleteFooAsync由于某种原因失败(或抛出异常),则用户或程序无法对其进行任何操作,因此我只想记录错误.
现在,我知道任何异常都会导致未观察到的异常,所以我能想到的最简单的情况是:
//In my code
Task deleteTask = DeleteFooAsync()
//In my App_Start
TaskScheduler.UnobservedTaskException += ( sender, e ) =>
{
m_log.Debug( "Unobserved exception! This exception would have been unobserved: {0}", e.Exception );
e.SetObserved();
};
Run Code Online (Sandbox Code Playgroud)
这样做有风险吗?
我能想到的另一个选择是制作我自己的包装器,例如:
private void async DeleteFooWrapperAsync()
{
try
{
await DeleteFooAsync();
}
catch(Exception …Run Code Online (Sandbox Code Playgroud) 我有一个Web服务器,并有定期作业合并和发送记录(许多请求日志).
Task.Run(() =>
{
while (true)
{
try
{
MergeAndPutRecords();
}
catch (Exception ex)
{
Logger.Error(ex);
}
}
});
Run Code Online (Sandbox Code Playgroud)
在MergeAndPutRecords函数中,有代码合并记录和异步函数返回任务发送记录.(实际上它是亚马逊Kinesis Firehose的PutRecordBatchAsync.)
如果我在没有await关键字的情况下调用该函数会发生什么?函数是否在单独的线程上运行?这里说它不是.那么什么是返回任务手段?这里说async方法没有等待关键字的意思
- 在当前线程上启动异步方法.忽略所有结果(包括例外).
然后同时处理我的定期作业和PutRecordBatchAsync?我知道asynchronouse和concurrent是不同的.但是没有await关键字,它们在同一个线程中.首先执行哪一个?我很困惑......
会有大量记录需要合并并实时发送.所以我认为它必须同时执行..
我们需要在我们的代码中写一些日志。
日志是通过记录一些信息的网络请求写入的(记录器是一个 Http-API 模块),但是如果 API 中有异常,我们不想中断整个流程。
我不Task.Run用于这种操作,因为它很糟糕。
但后来我想到了 non-awaitable-inline-function ,像这样:
private static readonly HttpClient client = new HttpClient();
void Main()
{
Console.WriteLine(1);
async Task LogMe()
{
var response = await client.PostAsync("http://www.NOTEXISTS.com/recepticle.aspx", null);
var responseString = await response.Content.ReadAsStringAsync();
//response.EnsureSuccessStatusCode(); // I don't need this here
Console.WriteLine("error");
}
//some code
LogMe();
//some code
Console.WriteLine(3);
}
Run Code Online (Sandbox Code Playgroud)
输出:
1
2
Run Code Online (Sandbox Code Playgroud)
题:
它是登录“即发即忘”模式的可行解决方案吗?
如果我在这个内联方法中创建对象,它们什么时候会被 GC 处理呢?
SemaphoreSlim.WaitAsync不管用。它跳转到调用完成return currentToken.AccessToken之前并抛出 NullException。GetAccesTokenAsync我也尝试使用 AsyncLock、AsyncSemaphore 和我在网上阅读的其他一些方法,但它似乎对我的情况不起作用。
public static class HttpClientHelper
{
#region members
private static SemaphoreSlim semaphore = new SemaphoreSlim(1, 1);
private static Token currentToken;
#endregion
public static string GetAuthorizeToken(ref HttpClient client, string username, string password)
{
GetToken(client, username, password);
return currentToken.AccessToken;
}
private static async void GetToken(HttpClient client, string username, string password)
{
await semaphore.WaitAsync();
try
{
if (currentToken == null)
{
await GetAccesTokenAsync(client, username, password);
}
else if (currentToken.IsExpired)
{
await GetAccessTokenByRefreshToken(client);
}
} …Run Code Online (Sandbox Code Playgroud) 编辑:为了澄清起见,这是在 Blazor 服务器应用程序中
我对 InvokeAsync 的正确用法和更新 UI 感到困惑。该文档有多种用法,但没有真正解释等待或不等待的原因。我也看到了一些相互矛盾的线索,但没有多少支持他们的推理。
使所有方法异步以等待 InvokeAsync(StateHasChanged) 似乎是错误的,我在某处读到引入 InvokeAsync 的原因是为了防止在任何地方都需要异步代码。但是在什么情况下我可能想要等待它?
等待:
非等待丢弃:
https://docs.microsoft.com/en-us/aspnet/core/blazor/components/rendering?view=aspnetcore-5.0
以下是我见过的一些不同用法的示例,如果有人可以解释或分享有关它们之间某些差异的信息的链接,那就太好了(谢谢!)
public void IncrementCounter()
{
_counter++;
InvokeAsync(StateHasChanged);
}
Run Code Online (Sandbox Code Playgroud)
public void IncrementCounter()
{
InvokeAsync(() =>
{
_counter++;
StateHasChanged);
}
}
Run Code Online (Sandbox Code Playgroud)
public async Task IncrementCounter()
{
_counter++;
await InvokeAsync(StateHasChanged);
}
Run Code Online (Sandbox Code Playgroud)
public async Task IncrementCounter()
{
await InvokeAsync(() =>
{
_counter++;
StateHasChanged();
});
}
Run Code Online (Sandbox Code Playgroud) 我正在寻找同步任务的最佳实践(甚至不确定这在语义上是否正确,我可能应该说用异步代码同步线程)。
采取以下代码:
Task.Run(async () => await lib.WaitAsync());
Task.Run(async () => await lib.WaitAsync());
Task.Run(async () => await lib.WaitAsync());
// Synchronize all waiters
lib.Release();
// All Tasks shall be completed
Run Code Online (Sandbox Code Playgroud)
在使用线程时,我曾经使用ManualResetEvent. 所以我的第一个(简化的)方法是:
Task WaitAsync()
{
await Task.Run(() => manualResetEvent.WaitOne());
}
void Release()
{
manualResetEvent.Set();
}
Run Code Online (Sandbox Code Playgroud)
现在我看到人们已经实现了自己的 async ManualResetEvent。
原始方法有什么问题以及为什么有人更喜欢异步实现?是因为取消了吗?异常展开/处理?
更一般地说,在异步代码中使用常规线程同步对象(互斥量、信号量等)是否有任何缺点?
谢谢
我对c# 中的async 和await 了解一些。但我看到了如图所示的返回视图的方法。所以我想知道这个方法是如何实现的?
我已经做到了这一点,
public async Task<PartialViewResult> SamplePartialPage()
{
ViewBag.countryList = await db.CountryList.ToListAsync();
return PartialView();
}
Run Code Online (Sandbox Code Playgroud)
但不是这个。
public async Task<PartialViewResult> SamplePartialPage()
{
ViewBag.countryList = await db.CountryList.ToListAsync();
return await Task.Run(() => PartialView());
}
Run Code Online (Sandbox Code Playgroud) 在 C# 中,我有一个例子:
public async static Task TaskTest(int i)
{
await Task.Delay(1);
Console.WriteLine($"{i}. {DateTime.Now.ToString("HH:mm:ss fff")} " +
$"ThreadId:{Thread.CurrentThread.ManagedThreadId} Start");
int count = 1;
while (true)
{
DoSomeThing(count);
var stopWatch = new Stopwatch();
stopWatch.Start();
await Task.Delay(100);
stopWatch.Stop();
if (stopWatch.Elapsed.TotalMilliseconds > 200)
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine($"Id:{count} Time:{DateTime.Now.ToString("HH:mm:ss fff")} " +
$"ThreadID:{Thread.CurrentThread.ManagedThreadId} Time Delay:{stopWatch.Elapsed.TotalMilliseconds }");
Console.ForegroundColor = ConsoleColor.White;
count++;
}
}
public async static Task DoSomeThing(int index)
{
await Task.Delay(1);
Task.Delay(1000).Wait();
}
private static void Main(string[] args)
{
int i = 1;
while …Run Code Online (Sandbox Code Playgroud) 在我的 ASP.NET Core 应用程序中,我以以下形式创建了几个(十几个)方法
public async Task DoStuff()
{
// ...
}
Run Code Online (Sandbox Code Playgroud)
所以,没有返回类型。
后来,我意识到我不小心忘记在调用方方法中到处包含此类方法(显然没有 async 关键字,因为异步“僵尸病毒”还没有传播那么远)。
在执行过程中,没有任何不良后果。
问题是,当这种事情发生时,Visual Studio 也不会生成任何警告消息,我问自己,在这种情况下,实际上是否存在忽略等待的危险?我知道 await 应该自然地应用于每个异步方法,但是当调用者实际上没有可使用的返回值时,我真的不明白这背后的原因。也许有捕获异常的东西?
我还没有找到任何明确的答案,因为一般声明是“只包含等待”。不管你信不信,这个异步/等待的东西,我相对较新,不时地反复咬我。