Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/ssh/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 编写自己的异步方法_C#_.net_Asynchronous_Task Parallel Library_Async Await - Fatal编程技术网

C# 编写自己的异步方法

C# 编写自己的异步方法,c#,.net,asynchronous,task-parallel-library,async-await,C#,.net,Asynchronous,Task Parallel Library,Async Await,我想知道如何以“正确”的方式编写自己的异步方法 我已经看到很多文章解释了异步/等待模式,如下所示: 您可能会注意到,更改是DoIndependentWork现在返回一个任务,并且在AccessTheWebAsync任务中,该方法得到了一个wait 重载操作现在被封装在一个任务中。Run(),只需要这些吗? 如果要为库中的每一个方法提供异步方法,我只需要这样做,请执行以下操作: public class FooMagic { public void DoSomeMagic() {

我想知道如何以“正确”的方式编写自己的异步方法

我已经看到很多文章解释了异步/等待模式,如下所示:

您可能会注意到,更改是
DoIndependentWork
现在返回一个任务,并且在
AccessTheWebAsync
任务中,该方法得到了一个
wait

重载操作现在被封装在一个
任务中。Run()
,只需要这些吗? 如果要为库中的每一个方法提供异步方法,我只需要这样做,请执行以下操作:

public class FooMagic
{
    public void DoSomeMagic()
    {
        //Do some synchron magic...
    }

    public Task DoSomeMagicAsync()
    {
        //Do some async magic... ?!?
        return Task.Run(() => { DoSomeMagic(); });
    }
}
如果你能给我解释一下就好了,因为即使是这样一个投票率很高的问题: 仅使用现有的方法解释,并且仅使用asyn/WAIT模式,如对上述问题的评论,将其带到要点:

实际答案 您可以使用,它有一个不执行任何代码的

表示未绑定到委托的任务的生产者端,通过任务属性提供对使用者端的访问

启动异步操作时将该任务返回给调用者,并在结束时设置结果(或异常/取消)。确保操作是真正异步的是您自己

下面是一个很好的示例,说明了这种实现中的所有异步方法的根:

class AsyncManualResetEvent 
{ 
    private volatile TaskCompletionSource<bool> _tcs = new TaskCompletionSource<bool>();

    public Task WaitAsync() { return _tcs.Task; } 
    public void Set() { _tcs.TrySetResult(true); } 
    public void Reset() 
    { 
        while (true) 
        { 
            var tcs = _tcs; 
            if (!tcs.Task.IsCompleted || 
                Interlocked.CompareExchange(ref _tcs, new TaskCompletionSource<bool>(), tcs) == tcs) 
                return; 
        } 
    } 
}
类异步手动重置事件
{ 
私有易失性TaskCompletionSource_tcs=新TaskCompletionSource();
公共任务WaitAsync(){return\u tcs.Task;}
public void Set(){u tcs.TrySetResult(true);}
公共无效重置()
{ 
while(true)
{ 
var tcs=_tcs;
如果(!tcs.Task.IsCompleted | |
Interlocked.CompareExchange(ref _tcs,new TaskCompletionSource(),tcs)=tcs)
返回;
} 
} 
}
背景 使用
async wait
基本上有两个原因:

  • 改进的可伸缩性:当您有
    I/O
    密集型工作(或其他固有的异步操作)时,您可以异步调用它,因此您可以释放调用线程,同时它还可以执行其他工作
  • 卸载:当您有
    CPU
    密集型工作时,您可以异步调用它,这将工作从一个线程转移到另一个线程(主要用于
    GUI
    线程)
  • 因此,
    Net
    框架的大多数异步调用都支持开箱即用的
    async
    ,用于卸载您使用的
    Task.Run
    (如您的示例所示)。只有在创建一个新的异步调用(
    I/O
    或async)时,才需要自己实现
    async

    这些案例极为罕见,这就是为什么你大部分都能找到这样的答案

    “仅使用现有的方法和使用
    async/await
    模式解释”


    你可以深入研究

    如果你能给我解释一下:如何编写简单的异步 方法

    首先,我们需要理解
    async
    方法的含义。当一个人向使用
    async
    方法的最终用户公开
    async
    方法时,你告诉他:“听着,这个方法会很快回到你身边,并承诺在不久的将来完成。”。这就是你向用户保证的

    现在,我们需要了解
    Task
    是如何使这一“承诺”成为可能的。正如您在问题中所问的,为什么只在我的方法中添加一个
    Task.Run
    ,就可以使用
    await
    关键字有效地等待

    Task
    实现了
    GetAwaiter
    模式,这意味着它返回一个名为
    awaiter
    的对象(实际调用的对象)。
    TaskAwaiter
    对象实现或接口,公开一个
    OnCompleted
    方法

    一旦使用了
    wait
    关键字,编译器就会依次使用所有这些好东西。编译器将确保在设计时,您的对象实现了
    GetAwaiter
    ,并反过来使用它将代码编译成状态机,这将使您的程序能够在等待后将控制权交还给调用方,并在工作完成后恢复

    现在,有一些指导方针需要遵循。真正的异步方法不会在幕后使用额外的线程来完成其工作(Stephan Cleary在中对此进行了精彩的解释),这意味着公开一个内部使用
    Task.Run
    的方法对api的使用者来说有点误导,因为他们会假定您的任务中不涉及额外的线程。你应该做的是同步公开你的API,让用户使用
    任务卸载它。自己运行
    ,控制执行流

    async
    方法主要用于I/O绑定的操作,因为在执行IO操作时,这些方法自然不需要消耗任何线程,这就是为什么我们在负责执行IO操作的类中看到它们的原因,例如硬盘驱动器调用、网络调用等

    我建议阅读《并行PFX团队》一文,该文准确地讲述了您正在尝试做什么以及为什么不推荐它。

    TL;博士:
    Task.Run()
    是您想要的,但要小心将其隐藏在库中

    我可能错了,但你可能正在寻找斯蒂芬·克利里(Stephen Cleary)的指导。我也很难找到这本书,我想它之所以这么难,是因为这不是你应该为图书馆做的事——有点

    文章 这篇链接文章读得很好(5-15分钟,视情况而定),详细介绍了将
    Task.Run()
    作为API的一部分与使用它来阻止UI线程的方法和原因,并区分了两种“类型”的lon
    public class FooMagic
    {
        public void DoSomeMagic()
        {
            //Do some synchron magic...
        }
    
        public Task DoSomeMagicAsync()
        {
            //Do some async magic... ?!?
            return Task.Run(() => { DoSomeMagic(); });
        }
    }
    
    class AsyncManualResetEvent 
    { 
        private volatile TaskCompletionSource<bool> _tcs = new TaskCompletionSource<bool>();
    
        public Task WaitAsync() { return _tcs.Task; } 
        public void Set() { _tcs.TrySetResult(true); } 
        public void Reset() 
        { 
            while (true) 
            { 
                var tcs = _tcs; 
                if (!tcs.Task.IsCompleted || 
                    Interlocked.CompareExchange(ref _tcs, new TaskCompletionSource<bool>(), tcs) == tcs) 
                    return; 
            } 
        } 
    }
    
    class MyService
    {
      public int CalculateMandelbrot()
      {
        // Tons of work to do in here!
        for (int i = 0; i != 10000000; ++i)
          ;
        return 42;
      }
    }
    
    ...
    
    private async void MyButton_Click(object sender, EventArgs e)
    {
      await Task.Run(() => myService.CalculateMandelbrot());
    }
    
    // Warning: bad code!
    class MyService
    {
      public int CalculateMandelbrot()
      {
        // Tons of work to do in here!
        for (int i = 0; i != 10000000; ++i)
          ;
        return 42;
      }
    
      public Task<int> CalculateMandelbrotAsync()
      {
        return Task.Run(() => CalculateMandelbrot());
      }
    }