Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/298.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# 参与者内部的异步API调用和异常_C#_Akka.net - Fatal编程技术网

C# 参与者内部的异步API调用和异常

C# 参与者内部的异步API调用和异常,c#,akka.net,C#,Akka.net,我知道,但是 所以,我的第一个问题[1]是:这里有没有什么“魔力”,让我们可以同步地等待一个延续中的嵌套任务,而它最终仍然是异步的 当我们处于异步&等待差异时,如何处理故障 让我们创建一个简单的示例: public static class AsyncOperations { public async static Task<int> CalculateAnswerAsync() { await Task.Delay(1000).ConfigureAw

我知道,但是

所以,我的第一个问题[1]是:这里有没有什么“魔力”,让我们可以同步地等待一个延续中的嵌套任务,而它最终仍然是异步的

当我们处于异步&等待差异时,如何处理故障

让我们创建一个简单的示例:

public static class AsyncOperations
{
    public async static Task<int> CalculateAnswerAsync()
    {
        await Task.Delay(1000).ConfigureAwait(false);
        throw new InvalidOperationException("Testing!");
        //return 42;
    }

    public async static Task<string> ConvertAsync(int number)
    {
        await Task.Delay(600).ConfigureAwait(false);
        return number + " :)";
    }
}
正如您预期的那样,异常将从第一个操作中冒出

现在,让我们创建一个参与者来处理这些异步操作。为了进行论证,假设
CalculateAnswerAsync
ConvertAsync
应作为一个完整的操作依次使用(例如,类似于
StreamWriter.WriteLineAsync
StreamWriter.FlushAsync
,如果您只想将一行写入流)

公共密封类AsyncTestActor:ReceiveActor
{
公开封条上课
{
}
公共密封类操作结果
{
私有只读字符串消息;
公共操作结果(字符串消息)
{
this.message=消息;
}
公共字符串消息
{
获取{返回消息;}
}
}
公共异步测试器()
{
接收(msg=>
{
AsyncOperations.CalculateAnswerAsync()
.ContinueWith(结果=>
{
变量编号=结果。结果;
var conversionTask=AsyncOperations.conversionAsync(数字);
转换任务。等待(1500);
返回新的操作结果(conversionTask.Result);
})
.派珀托(自我);
});
接收(msg=>Console.WriteLine(“Got”+msg.Message));
}
}
如果没有例外,我仍然得到
get 42:)
而没有任何问题,这让我回到了[1]上面的“魔术”点。 另外,示例中提供的
AttachedToParent
ExecuteSynchronously
标志是可选的,还是需要它们才能让一切按预期工作?它们似乎对异常处理没有任何影响

现在,如果
CalculateAnswerAsync
抛出一个异常,这意味着
result.result
抛出
aggregateeexception
,它几乎被吞没了,没有任何痕迹


如果可能的话,我应该在这里做什么,使异步操作中的异常像“常规”异常一样崩溃参与者?

TPL中错误处理的乐趣:)

一旦任务开始在它自己的线程上运行,它内部发生的所有事情都已经与调用方异步,包括错误处理
  • 当您在参与者内部启动第一个
    任务
    时,该任务在参与者的
    线程池
    上独立运行。这意味着在
    任务中执行的任何操作都将与参与者异步,因为它运行在不同的线程上。这是在你的文章的顶部。对参与者来说没有什么区别——它只是看起来像一个长期运行的任务
  • 异常-如果内部任务失败,
    conversionTask.Result
    属性将抛出在运行期间捕获的异常,因此您需要在
    任务
    中添加一些错误处理,以确保您的参与者收到出错的通知。请注意,我在这里就是这么做的:-如果你把你的例外变成你的演员可以处理的信息:鸟儿开始歌唱,彩虹闪烁,TPL错误不再是痛苦和痛苦的来源
  • 至于抛出异常时会发生什么
  • 现在,如果CalculateAnswerAsync抛出异常,这意味着 结果。结果抛出AggregateException,它几乎被吞没了 无影无踪

    aggregateeexception
    将包含封装在其中的内部异常列表-TPL之所以有聚合错误的概念,是因为(a)您有一个任务是聚合中多个任务的延续,即
    任务。whalll
    或(b)您的错误通过
    链向上传播到父级。您还可以调用
    AggregateException.flatte()
    调用,使管理嵌套异常变得更容易

    TPL+Akka.NET的最佳实践 处理来自TPL的异常是一件麻烦事,这是真的-但最好的处理方法是在
    任务中捕获..
    异常,并将它们转换为参与者可以处理的消息类

    另外,示例中提供的AttachedToParent和ExecuteSynchronously标志是可选的,还是它们是让一切按预期工作所必需的

    当您在continuations上有continuations时,这主要是一个问题-
    PipeTo
    会自动在自身上使用这些标志。它对错误处理没有任何影响,但可以确保您的继续立即在与原始
    任务
    相同的线程上执行


    我建议只在你进行大量嵌套的延续时才使用这些标志——一旦你进行了一次以上的延续,TPL就开始自由地安排你的任务(事实上,像OnlyOnCompleted这样的标志在进行了一次以上的延续后就不再被接受了。)

    只是为了补充Aaron所说的。 截至昨天,在使用任务调度器时,我们确实支持安全异步等待内部参与者

    public class AsyncAwaitActor : ReceiveActor
    {
        public AsyncAwaitActor()
        {
            Receive<string>(async m =>
            {
                await Task.Delay(TimeSpan.FromSeconds(1));
                Sender.Tell("done");
            });
        }
    }
    
    public class AskerActor : ReceiveActor
    {
        public AskerActor(ActorRef other)
        {
            Receive<string>(async m =>
            {
                var res = await other.Ask(m);
                Sender.Tell(res);
            });
        }
    }
    
    public class ActorAsyncAwaitSpec : AkkaSpec
    {
        [Fact]
        public async Task Actors_should_be_able_to_async_await_ask_message_loop()
        {
            var actor = Sys.ActorOf(Props.Create<AsyncAwaitActor>()
            .WithDispatcher("akka.actor.task-dispatcher"),
                "Worker");
            //IMPORTANT: you must use the akka.actor.task-dispatcher
            //otherwise async await is not safe
    
            var asker = Sys.ActorOf(Props.Create(() => new AskerActor(actor))
            .WithDispatcher("akka.actor.task-dispatcher"),
                "Asker");
    
            var res = await asker.Ask("something");
            Assert.Equal("done", res);
        }
    }
    
    公共类AsyncWaitActor:ReceiveActor
    {
    公共参与者()
    {
    接收(异步m=>
    {
    等待任务延迟(时间跨度从秒(1));
    发送人。告知(“完成”);
    });
    }
    }
    公共类AskerActor:ReceiveActor
    {
    公众咨询人(其他行为人)
    {
    接收(异步m=>
    
    public sealed class AsyncTestActor : ReceiveActor
    {
        public sealed class Start
        {
        }
    
        public sealed class OperationResult
        {
            private readonly string message;
    
            public OperationResult(string message)
            {
                this.message = message;
            }
    
            public string Message
            {
                get { return message; }
            }
        }
    
        public AsyncTestActor()
        {
            Receive<Start>(msg =>
                   {
                       AsyncOperations.CalculateAnswerAsync()
                         .ContinueWith(result =>
                                {
                                    var number = result.Result;
                                    var conversionTask = AsyncOperations.ConvertAsync(number);
                                    conversionTask.Wait(1500);
                                    return new OperationResult(conversionTask.Result);
                                })
                         .PipeTo(Self);
                    });
            Receive<OperationResult>(msg => Console.WriteLine("Got " + msg.Message));
        }
    }
    
    public class AsyncAwaitActor : ReceiveActor
    {
        public AsyncAwaitActor()
        {
            Receive<string>(async m =>
            {
                await Task.Delay(TimeSpan.FromSeconds(1));
                Sender.Tell("done");
            });
        }
    }
    
    public class AskerActor : ReceiveActor
    {
        public AskerActor(ActorRef other)
        {
            Receive<string>(async m =>
            {
                var res = await other.Ask(m);
                Sender.Tell(res);
            });
        }
    }
    
    public class ActorAsyncAwaitSpec : AkkaSpec
    {
        [Fact]
        public async Task Actors_should_be_able_to_async_await_ask_message_loop()
        {
            var actor = Sys.ActorOf(Props.Create<AsyncAwaitActor>()
            .WithDispatcher("akka.actor.task-dispatcher"),
                "Worker");
            //IMPORTANT: you must use the akka.actor.task-dispatcher
            //otherwise async await is not safe
    
            var asker = Sys.ActorOf(Props.Create(() => new AskerActor(actor))
            .WithDispatcher("akka.actor.task-dispatcher"),
                "Asker");
    
            var res = await asker.Ask("something");
            Assert.Equal("done", res);
        }
    }