在同步线程安全中访问异步任务<x> .Result?</x>

时间:2012-12-17 04:59:23

标签: c# asynchronous thread-safety .net-4.5

如果我有.NET 4.5异步任务方法,例如:

 public async Task<String> GetData()

 (...)

 return await MyObject.GetSomethingAsynchronous();

然后在同步线程中的其他位置(例如非异步方法),我称之为:

 String myString = MyObject.GetData().Result;

这样做或做法不好吗?

2 个答案:

答案 0 :(得分:2)

通常不建议拨打Task.Result。更好的解决方案是await Task并将包含方法更改为async,从而允许异步代码在代码库中成长。

Task.Result相比,await存在两个问题(除了它阻止而不是异步等待的事实):

  1. 您可以轻松进入死锁情况,其中Task需要特定线程(例如,UI线程)才能完成,但该线程在Task上被阻止。我会更详细地解释这一点on my blog
  2. async方法引发的任何错误都将包含在AggregateException中,这会使异常处理变得更加复杂。 await将解包基础错误,允许您使用更自然的catch(MyExceptionType)

答案 1 :(得分:0)

基本上是的。

根据您提出的问题,我认为您认为Tasksomething executed in separate thread并不一定正确。 Asyc机制比那更通用,它允许在你等待的同时做东西 - 让线程结束为一个,web请求返回值,文件系统读取文件,以及你想要的任何其他东西。这只不过是花哨的语法糖,让你不会被这样的模式困扰:

void DoSomethingTimeConsumingThatWillNotBlockThisThread(Action onFinishContinue);

考虑这个简单的程序:

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    protected override void OnLoad(EventArgs e)
    {
        GetPoint();
    }

    public async void GetPoint()
    {
        var point = await RetrivePointAsync();
        MessageBox.Show(point.ToString());
    }

    public Task<Point> RetrivePointAsync()
    {
        return Task.Factory.FromAsync<Point>(
             (callback, state) => new Handler(this, callback),
             x => ((Handler)x).Point, null);
    }
}

只是为了证明我的观点,我附加了事件,我正在等待用户点击,因此不涉及任何线程。

class Handler : IAsyncResult
{
    AsyncCallback _calback;
    public Point Point { get; set; }
    public object AsyncState { get { return null; } }
    public bool CompletedSynchronously { get { return false; } }
    public bool IsCompleted { get; set; }

    public WaitHandle AsyncWaitHandle { get { return null; } }

    public Handler(Control control, AsyncCallback calback)
    {
        _calback = calback;
        control.MouseDown += control_MouseDown;
    }

    void control_MouseDown(object sender, MouseEventArgs e)
    {
        Point = e.Location;
        IsCompleted = true;
        _calback(this);
    }
}