Multithreading 如何防止我的Akka.net actor阻止我的整个actor系统?

Multithreading 如何防止我的Akka.net actor阻止我的整个actor系统?,multithreading,concurrency,akka.net,Multithreading,Concurrency,Akka.net,我有一个C#Akka.net项目,使用6名演员。一个参与者(LoggingActor)负责获取对象并将其传输到web服务器 每当LoggingActor遇到网络故障时,它似乎会瓶颈我的整个actor系统;一切都会暂停,直到LoggingActor完成其方法 LoggingActor中的阻塞方法包含以下内容: try { var rs = new RemoteServer(); var rsr = rs.SendMovement(editedMovement, _regionCon

我有一个C#Akka.net项目,使用6名演员。一个参与者(LoggingActor)负责获取对象并将其传输到web服务器

每当LoggingActor遇到网络故障时,它似乎会瓶颈我的整个actor系统;一切都会暂停,直到LoggingActor完成其方法

LoggingActor中的阻塞方法包含以下内容:

try
{
    var rs = new RemoteServer();
    var rsr = rs.SendMovement(editedMovement, _regionConfig.SiteToken, _userConfig.ServerUrl)
        .Result;
    if (rsr != HttpStatusCode.OK)
    {
        Log("Movement POST failed:" + rsr, LogLevel.Error, "LoggingActor");
    }
}
catch (HttpRequestException httpEx)
{
    Log("Buffering movement for re-send", LogLevel.Warn, "LoggingActor");
    MovementTransmitBuffer.Add(editedMovement);
}
SendMovement函数如下所示:

public async Task<HttpStatusCode> SendMovement(Movement movement, string siteToken, string serverUrl)
{ 
    //Get remote server
    var createMovementUrl = serverUrl + MovementsRoute + "?site_token=" + siteToken;
    var jsonString = "{ \"movement\": { \"approach\": \"" + movement.Approach + "\", \"exit\": \"" + movement.Exit + "\", \"turntype\": \"" + movement.TurnType + "\", \"objectclass\": \"" + movement.TrafficObjectType + "\", \"created_at\": " + movement.Timestamp.Ticks +  "} }";
    var content = new StringContent(jsonString, Encoding.UTF8, "application/json");

    //Transmit
    var response = await Client.PostAsync(createMovementUrl, content);
    return response.StatusCode;
}
公共异步任务SendMovement(移动、字符串siteToken、字符串serverUrl) { //获取远程服务器 var createMovementUrl=serverUrl+MovementsRoute+“?site_token=“+siteToken; var jsonString=“{\'movement\”:{\'approach\”:\“+movement.approach+”,“exit\”:\“+movement.exit+”,“turntype\”:\“+movement.turntype+”,“objectclass\”:\“+movement.TrafficObjectType+”,“created\u at\”:“+movement.Timestamp.Ticks+”}”; var content=newstringcontent(jsonString,Encoding.UTF8,“application/json”); //传送 var response=wait Client.PostAsync(createMovementUrl,content); 返回response.StatusCode; } LoggingActor的目的是尝试将我的对象发布到服务器,并缓冲它们,以便在初始尝试失败时稍后发送。它们在我的应用程序中传输的顺序并不重要

我如何修改LoggingActor或SendMovement函数,允许LoggingActor通过在等待响应之前发送POST请求来“破坏”LoggingActor的消息处理功能


我想我想要的是服务器的POST响应(或异常)触发另一条消息给参与者,该消息告诉参与者将其从发送队列中删除或保留(即不执行任何操作)。

您正在调用
rs.sendmation
,它返回一个任务,您正在调用
结果
属性。这将锁定当前线程池中的整个线程-因为线程池在使用它的所有参与者/任务之间共享,并且通常每个CPU核心包含一个工作线程。这意味着您已经有效地关闭了整个CPU核心,直到远程端响应(或者超时发生)

一般来说,在处理异步代码时,不应该阻塞线程。在Akka.NET中,使用基于任务的API可以通过以下两种方式之一完成

使用
ReceiveAsync
第一种解决方案是让您的参与者从
ReceiveActor
继承,并使用
ReceiveAsync
方法定义您的消息处理程序:

类MyActor:ReceiveActor
{
公共MyActor()
{
ReceiveAsync(异步消息=>{
尝试
{
var rs=新的远程服务器();
var rsr=wait rs.SendMovement(editedMovement,\u regionConfig.SiteToken,\u userConfig.ServerUrl);
if(rsr!=HttpStatusCode.OK)
{
日志(“移动POST失败:+rsr,LogLevel.Error,“LoggingActor”);
}
}
捕获(HttpRequestException httpEx)
{
日志(“为重新发送缓冲移动”,LogLevel.Warn,“LoggingActor”);
移动传输缓冲添加(编辑移动);
}
});
}
}
这将创建一个称为不可重入的actor的东西-这意味着,虽然您不会阻止任何底层线程(这样它仍然可以被并发工作的其他actor使用),但您将阻止当前actor,阻止它接收任何其他消息,直到当前异步lambda处理程序到达末尾

使用
PipeTo
另一种方法——默认情况下在几乎所有akka内部架构中使用——是在任务上使用
PipeTo
方法:

类MyActor:ActorBase
{
//从处于就绪状态的参与者开始
受保护的覆盖布尔接收(对象消息)=>Ready(消息);
bool就绪(对象消息)
{
开关(信息)
{
案例MyMessage消息:
var rs=新的远程服务器();
rs.SendMovement(editedMovement,_regionConfig.SiteToken,_userConfig.ServerUrl)
.派珀,
成功:rsr=>新状态。成功(rsr),
失败:ex=>newstatus.failure(ex));
变成(等待);
返回true;
默认:返回false;
}
}
布尔等待(对象消息)
{
开关(信息)
{
案例状态。成功:
var rsr=(HttpStatusCode)success.Status;
if(rsr!=HttpStatusCode.OK)
{
日志(“移动POST失败:+rsr,LogLevel.Error,“LoggingActor”);
}
准备好;
返回true;
案例状态。失败:
日志(“为重新发送缓冲移动”,LogLevel.Warn,“LoggingActor”);
移动传输缓冲添加(编辑移动);
准备好;
返回true;
默认:返回false;
}
}
}
这样,您就可以将您的参与者转换为自定义状态机。此处负责等待逻辑的代码分为两个步骤-此处表示为
Ready
/
Waiting
状态。在发送异步请求后,actor正在更改其行为,这意味着他现在可以处理不同的传入消息集或对它们做出不同的反应。返回的布尔值通知参与者系统消息是否由当前参与者处理-这可能会触发未处理的调用,默认情况下将记录未处理的消息

这种方法的优点之一是该参与者是可重入的,这意味着在等待
发送移动
返回结果(或失败)时,该参与者可以自由接收和处理其他消息<