在任何情况下,异步等待方法中的对象更改在完成后是否可见?
Are object changes inside async await methods visible after completion in any case?
async/await 方法内的对象更改在任何情况下都可见吗?
经过大量调查,我仍然找不到明确的声明,如果在完成等待 in 之后,从异步等待方法内部对外部对象进行的更新对后续代码可见案例.
代码示例是某种过滤器链,其中每个过滤器都应该看到之前过滤器所做的任何更改。之后,将使用相同的对象进行进一步处理。
没有并行执行过滤器。除此之外,由于性能原因,我不想克隆对象。
请看下面的代码示例:
class Program
{
private List<ICallback> _allCallbacks = new List<ICallback>();
public Program()
{
// Setup callbacks, perhaps by dependency injection
_allCallbacks.Add(new MyCallback1());
_allCallbacks.Add(new MyCallback2());
}
static async Task Main()
{
Program p = new Program();
await p.RunBusinessLogic();
Console.ReadLine();
}
private async Task RunBusinessLogic()
{
MyDto dto = new MyDto();
// Setting initial value
dto.TestProperty = "start";
// Execute all callbacks and await completion
await ExecuteCallbacks(dto).ConfigureAwait(false);
// *** Is dto.TestProperty always guaranteed to be most current value ***?
Console.WriteLine(dto.TestProperty); // start-1-2?
}
public async Task ExecuteCallbacks(MyDto source)
{
foreach (ICallback callback in _allCallbacks)
{
// Execute Callbacks one after the other, no parallel execution here
await callback.OnCallback(source).ConfigureAwait(false);
}
}
public class MyDto
{
public string TestProperty { get; set; }
}
public interface ICallback
{
public Task OnCallback(MyDto dto);
}
public class MyCallback1 : ICallback
{
public async Task OnCallback(MyDto x)
{
x.TestProperty += "-1";
await Task.CompletedTask.ConfigureAwait(false);
}
}
public class MyCallback2 : ICallback
{
public async Task OnCallback(MyDto x)
{
x.TestProperty += "-2";
await Task.CompletedTask.ConfigureAwait(false);
}
}
}
可能相关:
这是一个非常合理的担忧,如果 C# 规范和 CLI 规范都有更清晰的内存模型来保证这一点,那就太好了。
不,我不相信有任何 Microsoft 记录 保证当任务完成(无论是成功还是失败)并且继续执行时,所有内存都会改变在任务中执行对后续代码可见。
但是,我相信 务实的现实 是的,所有更改都将是可见的,就好像在任务完成时存在完整的内存障碍一样。看起来像 Joe Albahari asserts that this is the case,但我希望看到更多“出自马口”的保证。
JIT 编译器在理论上 允许做的事情还有其他一些类似的方面 - 这比 JIT 编译器作者认为合理的要多得多做。随着时间的推移,我希望看到关于此的更详细的保证,但我对这种情况的发生并没有太大的信心。
async/await 方法内的对象更改在任何情况下都可见吗?
经过大量调查,我仍然找不到明确的声明,如果在完成等待 in 之后,从异步等待方法内部对外部对象进行的更新对后续代码可见案例.
代码示例是某种过滤器链,其中每个过滤器都应该看到之前过滤器所做的任何更改。之后,将使用相同的对象进行进一步处理。
没有并行执行过滤器。除此之外,由于性能原因,我不想克隆对象。
请看下面的代码示例:
class Program
{
private List<ICallback> _allCallbacks = new List<ICallback>();
public Program()
{
// Setup callbacks, perhaps by dependency injection
_allCallbacks.Add(new MyCallback1());
_allCallbacks.Add(new MyCallback2());
}
static async Task Main()
{
Program p = new Program();
await p.RunBusinessLogic();
Console.ReadLine();
}
private async Task RunBusinessLogic()
{
MyDto dto = new MyDto();
// Setting initial value
dto.TestProperty = "start";
// Execute all callbacks and await completion
await ExecuteCallbacks(dto).ConfigureAwait(false);
// *** Is dto.TestProperty always guaranteed to be most current value ***?
Console.WriteLine(dto.TestProperty); // start-1-2?
}
public async Task ExecuteCallbacks(MyDto source)
{
foreach (ICallback callback in _allCallbacks)
{
// Execute Callbacks one after the other, no parallel execution here
await callback.OnCallback(source).ConfigureAwait(false);
}
}
public class MyDto
{
public string TestProperty { get; set; }
}
public interface ICallback
{
public Task OnCallback(MyDto dto);
}
public class MyCallback1 : ICallback
{
public async Task OnCallback(MyDto x)
{
x.TestProperty += "-1";
await Task.CompletedTask.ConfigureAwait(false);
}
}
public class MyCallback2 : ICallback
{
public async Task OnCallback(MyDto x)
{
x.TestProperty += "-2";
await Task.CompletedTask.ConfigureAwait(false);
}
}
}
可能相关:
这是一个非常合理的担忧,如果 C# 规范和 CLI 规范都有更清晰的内存模型来保证这一点,那就太好了。
不,我不相信有任何 Microsoft 记录 保证当任务完成(无论是成功还是失败)并且继续执行时,所有内存都会改变在任务中执行对后续代码可见。
但是,我相信 务实的现实 是的,所有更改都将是可见的,就好像在任务完成时存在完整的内存障碍一样。看起来像 Joe Albahari asserts that this is the case,但我希望看到更多“出自马口”的保证。
JIT 编译器在理论上 允许做的事情还有其他一些类似的方面 - 这比 JIT 编译器作者认为合理的要多得多做。随着时间的推移,我希望看到关于此的更详细的保证,但我对这种情况的发生并没有太大的信心。