您在那儿,异步编写值吗? [英] Are you there, asynchronously written value?

查看:74
本文介绍了您在那儿,异步编写值吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

最近几天,我一直在阅读有关异步/等待的内容.昨天我发现此视频使某些事情产生了疑问.请考虑下面的幻灯片.

除了Lucian Wischik解决的问题之外,我还想知道变量分配.假设我们将async void更改为async Task,并在SendData调用之前添加了await.这使我们能够获取流,分配变量m_GetResponse,等待两秒钟并进行打印.但是变量会发生什么呢?它可以由与读取的线程不同的线程写入.在这里,我们是否需要某种内存屏障,使变量可变,或者其他?当我们打印它时,它仍然可以为空吗?

解决方案

在上面的示例中,读取m_GetResponse是安全的,因为假定从UI调用该赋值将在同一UI线程中发生. >

这是因为SynchronizationContext将在异步方法恢复时被捕获并继续.因此,这是写入字段并读取字段的UI线程.这不是问题.在这里参考我的相关答案

如果从非UI上下文调用,则不能保证继续将在同一线程中运行.通常它将在ThreadPool线程中运行.鉴于字段读取不是易变的,如果没有插入必要的障碍,则有可能获得先前的值.但是您不必担心,因为 TPL已经为您做到了

通过上面的链接

是的,当任务排队时,TPL包含适当的障碍,并且 在任务执行的开始/结束时,值是 适当地显示出来

因此,使用TPL,鉴于任务已经完成,因此您无需担心内存障碍.但是,如果要手动创建线程(不应该这样做)并直接处理线程,则必须插入必要的内存屏障.

顺便说一句,ReadToEnd是阻止呼叫.我不会在UI线程中调用它.我会使用ReadToEndAsync代替您的UI线程.而且我不会在这里使用字段;我将从异步方法中返回值,因为每个方法调用都仅依赖于参数,因此从方法中返回值是有意义的.

因此,您的方法将如下所示

private async Task<string> SendDataAsync(string url)
{
    var request = WebRequest.Create(url);
    using(var response = await request.GetResponseAsync());
    using(var reader = new StreamReader(request.GetResponseStream());
        return await reader.ReadToEndAsync();
}

The last couple of days I've been reading about async/await. Yesterday I found this video on Channel 9 what made wonder about some things. Please consider the slide below.

Aside from the issues Lucian Wischik addresses, I wondered about variable assignment. Say we changed the async void into async Task, and added await before the SendData call. This enables us to get the stream, assign the variable m_GetResponse, wait for two seconds and print it. But what happens to the variable? It could be written by a different thread than it is read. Do we need some sort of a memory barrier here, make the variable volatile, or perhaps something else? Could it still be null when we print it?

解决方案

In the above example, it is safe to read the m_GetResponse because assignment will happen in same UI thread given that this is being called from UI.

This is because SynchronizationContext will be captured and continued when the async method resumes. So it is the same UI thread which writes the field and reading it. This isn't a problem here. Refer my related answer here

If called from non UI context, there is no guarantee that continuations will be ran in same thread. Usually it will be ran in ThreadPool thread. Given that the field read isn't volatile it is possible that you could get the previous value if necessary barriers are not inserted. But you don't need to worry about it because TPL already does this for you.

From the above link

Yes, TPL includes the appropriate barriers when tasks are queued and at the beginning/end of task execution so that values are appropriately made visible

So with TPL, you don't need to worry about memory barriers given that the Tasks are already completed. But if you're creating threads manually(which you shouldn't be doing) and dealing with threads directly --you'll have to insert necessary memory barriers.

Btw, ReadToEnd is a blocking call. I would not call it in UI thread. I'd use ReadToEndAsync instead to make your UI thread free. And I'll not use field here; I'll return the value from async method because every method call is just dependent on the parameter so it makes sense to return the value from the method.

So, your method will become something like the following

private async Task<string> SendDataAsync(string url)
{
    var request = WebRequest.Create(url);
    using(var response = await request.GetResponseAsync());
    using(var reader = new StreamReader(request.GetResponseStream());
        return await reader.ReadToEndAsync();
}

这篇关于您在那儿,异步编写值吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆