当你有服务器端代码(即一些ApiController)并且你的函数是异步的 - 所以它们返回Task<SomeObject>- 你认为最好的做法是等待你调用的函数ConfigureAwait(false)吗?
我已经读过它更高效,因为它不必将线程上下文切换回原始线程上下文.但是,使用ASP.NET Web Api,如果您的请求是在一个线程上进行的,并且等待某些函数和调用ConfigureAwait(false),则可能会在返回ApiController函数的最终结果时将您置于不同的线程上.
我在下面输入了一个我正在谈论的例子:
public class CustomerController : ApiController
{
public async Task<Customer> Get(int id)
{
// you are on a particular thread here
var customer = await SomeAsyncFunctionThatGetsCustomer(id).ConfigureAwait(false);
// now you are on a different thread! will that cause problems?
return customer;
}
}
Run Code Online (Sandbox Code Playgroud) 我想问你关于正确架构何时使用的意见Task.Run.我在WPF .NET 4.5应用程序(使用Caliburn Micro框架)中遇到了滞后的UI.
基本上我在做(非常简化的代码片段):
public class PageViewModel : IHandle<SomeMessage>
{
...
public async void Handle(SomeMessage message)
{
ShowLoadingAnimation();
// Makes UI very laggy, but still not dead
await this.contentLoader.LoadContentAsync();
HideLoadingAnimation();
}
}
public class ContentLoader
{
public async Task LoadContentAsync()
{
await DoCpuBoundWorkAsync();
await DoIoBoundWorkAsync();
await DoCpuBoundWorkAsync();
// I am not really sure what all I can consider as CPU bound as slowing down the UI
await DoSomeOtherWorkAsync();
}
}
Run Code Online (Sandbox Code Playgroud)
从我阅读/看到的文章/视频中,我知道await async不一定在后台线程上运行,并且需要在后台开始工作,需要等待它Task.Run(async () => …
我正在学习async/await,在我读完这篇文章之后不要阻止异步代码
我从@Stephen Cleary的文章中注意到了一个提示.
使用ConfigureAwait(false)来避免死锁是一种危险的做法.您必须对阻塞代码调用的所有方法的传递闭包中的每个等待使用ConfigureAwait(false),包括所有第三方和第二方代码.使用ConfigureAwait(false)来避免死锁充其量只是一个黑客攻击.
它在我上面附上的帖子代码中再次出现.
public async Task<HtmlDocument> LoadPage(Uri address)
{
using (var httpResponse = await new HttpClient().GetAsync(address)
.ConfigureAwait(continueOnCapturedContext: false)) //IO-bound
using (var responseContent = httpResponse.Content)
using (var contentStream = await responseContent.ReadAsStreamAsync()
.ConfigureAwait(continueOnCapturedContext: false)) //IO-bound
return LoadHtmlDocument(contentStream); //CPU-bound
}
Run Code Online (Sandbox Code Playgroud)
据我所知,当我们使用ConfigureAwait(false)时,其余的异步方法将在线程池中运行.为什么我们需要在传递闭包中将它添加到每个等待中?我自己只是认为这是我所知道的正确版本.
public async Task<HtmlDocument> LoadPage(Uri address)
{
using (var httpResponse = await new HttpClient().GetAsync(address)
.ConfigureAwait(continueOnCapturedContext: false)) //IO-bound
using (var responseContent = httpResponse.Content)
using (var contentStream = await responseContent.ReadAsStreamAsync()) //IO-bound
return LoadHtmlDocument(contentStream); //CPU-bound
}
Run Code Online (Sandbox Code Playgroud)
这意味着在使用块中第二次使用ConfigureAwait(false)是没用的.请告诉我正确的方法.提前致谢.
我遇到了一个任务正在完成但没有返回的问题.我在不同的服务器上有一个网站和一个Web服务.该网站调用Web服务,该服务使用具有函数myFunction()的库.如果我从Web服务的服务器上的控制台应用程序调用myFunction,它将按预期返回.但是,当我从网站拨打电话到Web服务来调用myFunction()时,它将进入"步骤3",而不是"步骤4".我有以下调用的简化版本.
private string myFunction()
{
string myStr = myDoWork().GetAwaiter().GetResult();
return myStr;
}
private async Task<string> myDoWork()
{
logger.Debug("Step 1");
string answer = await aFunction();
logger.Debug("Step 4");
return answer;
}
public async Task<string> aFunction()
{
logger.Debug("Step 2");
return await bFunction(CancellationToken.None);
}
AsyncLock myLock = new AsyncLock();
public Task<string> bFunction(CancellationToken cToken)
{
return Task.Run(
async () =>
{
using (await myLock(cToken))
{
logger.Debug("Step 3");
result = "Hello";
return result;
}
},
cToken);
}
Run Code Online (Sandbox Code Playgroud)
我是异步和等待的新手,所以任何帮助都将不胜感激.
在Unity中,说您有一个GameObject。因此,可能是劳拉·克罗夫特(Lara Croft),马里奥(Mario),愤怒的鸟,特定的立方体,特定的树或其他任何东西。
(回想一下,Unity不是OO,它是ECS。Component可以“附加”到s的s本身可以GameObject用OO语言创建,也可以不使用OO语言创建,但是Unity本身只是GameObjects 的列表和运行任何Components 的框架引擎。因此,实际上Unity当然是“完全”的单线程,甚至没有一种概念上的方法可以在另外1个线程上执行与“实际Unity”(“游戏对象列表”)相关的任何操作。)
所以说在多维数据集上,我们有一个Component称为Test
public class Test: MonoBehaviour {
Run Code Online (Sandbox Code Playgroud)
它确实具有Update伪函数,因此Unity知道我们要在每个帧中运行一些东西。
private void Update() { // this is Test's Update call
Debug.Log(ManagedThreadId); // definitely 101
if (something) DoSomethingThisParticularFrame();
}
Run Code Online (Sandbox Code Playgroud)
假设统一线程为“ 101”。
这样更新(实际上是任何游戏对象上任何框架的任何更新)都将打印101。
因此,由于某种原因,我们有时会选择每隔几秒钟运行一次DoSomethingThisFrame。
因此,每一帧(显然,在“该” Unity线程上……有/只能有一个线程),Unity在各种游戏对象上运行所有Update调用。
因此,在一个特定的帧(比如说游戏的第819秒的第24帧)上,它确实DoSomethingThisParticularFrame为我们运行。
void DoSomethingThisParticularFrame() {
Debug.Log(ManagedThreadId); // 101 I think
TrickyBusiness();
}
Run Code Online (Sandbox Code Playgroud)
我认为这也会打印101。
async void TrickyBusiness() {
Debug.Log("A.. " + ManagedThreadId); // 101 I think
var aTask …Run Code Online (Sandbox Code Playgroud) 问题不在于 ConfigureAwait 做什么。但更确切地说,为什么我到处都能看到类似的东西
一般来说,是的。除非该方法需要其上下文,否则应为每个等待使用 ConfigureAwait(false)。
即他们建议我应该写
await Method1().ConfigureAwait(false);
await Method2().ConfigureAwait(false);
// Do something else
// ...
await Method3().ConfigureAwait(false);
await Method4().ConfigureAwait(false);
Run Code Online (Sandbox Code Playgroud)
但在这种情况下,只在一开始就重置上下文不会更清楚,就像
await Task.Yield().ConfigureAwait(false);
Run Code Online (Sandbox Code Playgroud)
它保证下面的代码将在没有同步上下文的情况下执行,不是吗?
即我读到如果该方法立即返回,则写一次 ConfigureAwait 可能不起作用。对我来说,显而易见的解决方案看起来像调用 ConfigureAwait(false) 肯定不会立即返回的东西,Task.Yield 是什么,对吧?
另外我知道 Task.Yield 不再包含 ConfigureAwait(不知道为什么,因为我知道它以前曾经有它),但是查看 Task.Yield 代码很容易编写自己的方法除了用空的同步上下文调用延续之外,什么都不做。
对我来说,阅读似乎要容易得多,尤其是当你写一次的时候写
await TaskUtility.ResetSyncContext();
Run Code Online (Sandbox Code Playgroud)
而不是在每一行上写 ConfigureAwait。
这会起作用(Task.Yield().ConfigureAwait(false) 或类似的自定义方法)还是我错过了什么?