您在那儿,异步编写值吗? [英] Are you there, asynchronously written value?
问题描述
最近几天,我一直在阅读有关异步/等待的内容.昨天我发现此视频使某些事情产生了疑问.请考虑下面的幻灯片.
除了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屋!