C#异步:线程如何记住其局部变量?

时间:2019-03-01 09:44:37

标签: c# multithreading asynchronous async-await

在多线程中,线程共享一些东西,但不共享局部变量。每个线程维护其自己的堆栈副本,该副本存储本地变量。很好,但是在这种情况下会发生什么?

public async Task<string> ReadFile()
{
    var fileName = GenerateFileName();

    using (var reader = File.OpenText(fileName))
    {
        var fileText = await reader.ReadToEndAsync();
        return fileName + "|" + fileText;
    }
}

当IO操作开始时,线程进入睡眠状态(或执行其他操作),而当线程(或其他线程)返回以继续执行该功能时,它如何记住fileName的值?堆栈在这里发生了什么?

1 个答案:

答案 0 :(得分:3)

它的发生方式与yield方法存储其本地变量的方式类似:它创建一个struct,该变量具有C#中本地变量作为字段。

因此,如果aysnc不存在,您的代码将产生某些编码,例如:

private struct ReadFileAsyncStateMachine : IAsyncStateMachine
{
    public int _state;
    public AsyncTaskMethodBuilder<string> _builder;
    private string _fileName;
    private string _fileText;
    private StreamReader _reader;
    TaskAwaiter<string> _awaiter;
    void IAsyncStateMachine.MoveNext()
    {
        try
        {
            if (_state != 0)
            {
                goto afterSetup;
            }

            _fileName = GenerateFileName();
            _reader = File.OpenText(_fileName);
            TaskAwaiter<string> awaiter = _reader.ReadToEndAsync().GetAwaiter();
            _state = -1;
            if (!awaiter.IsCompleted)
            {
                _awaiter = awaiter;
                _builder.AwaitUnsafeOnCompleted<TaskAwaiter<string>, ReadFileAsyncStateMachine>(ref awaiter, ref this);
                return;
            }

        afterSetup:
            awaiter = _awaiter;
            _fileText = awaiter.GetResult();
            _state = -2;
            _builder.SetResult(_fileName + "|" + _fileText);
            _reader.Dispose();
        }
        catch (Exception exception)
        {
            _state = -2;
            _builder.SetException(exception);
            _reader?.Dispose();
            return;
        }
    }
    [DebuggerHidden]
    void IAsyncStateMachine.SetStateMachine(IAsyncStateMachine param0)
    {
        _builder.SetStateMachine(param0);
    }
}

public Task<string> ReadFile()
{
    ReadFileAsyncStateMachine stateMachine = new ReadFileAsyncStateMachine();
    AsyncTaskMethodBuilder<string> builder = AsyncTaskMethodBuilder<string>.Create();

    stateMachine._builder = builder;
    stateMachine._state = -1;
    builder.Start(ref stateMachine);
    return builder.Task;
}

ReadFileAsyncStateMachine处理ReadToEndAsync()立即完成的可能性,在这种情况下,返回的Task<string>立即完成并且有结果或正在运行,在这种情况下,{{1返回的}}本身正在运行,随后对Task<string>的调用将完成它。异常也得到处理。

如您所见,C#中的本地语言是实现中的字段。