Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/299.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#_Task Parallel Library - Fatal编程技术网

C# 我能';我不理解此异步场景的行为

C# 我能';我不理解此异步场景的行为,c#,task-parallel-library,C#,Task Parallel Library,我正在开发一个EventManager,负责注册一些订阅者,并在引发事件时通知他们。 我想模拟一个循环场景,找到一种防止它的方法。下面是我编写的测试: [Test] public void LoopTest() { var eventManager = new EventManager(); eventManager.IntroduceEvent("A",typeof(EventArgs)); eventManager.IntroduceEvent("B", typeof

我正在开发一个
EventManager
,负责注册一些
订阅者
,并在引发事件时通知他们。 我想模拟一个循环场景,找到一种防止它的方法。下面是我编写的测试:

[Test]
public void LoopTest()
{
    var eventManager = new EventManager();
    eventManager.IntroduceEvent("A",typeof(EventArgs));
    eventManager.IntroduceEvent("B", typeof(EventArgs));

    eventManager.Subscribe<EventArgs>("A", (sender, args) =>
    {
        Console.WriteLine("Raise B");
        eventManager.RaiseAsync("B", sender, args);
    });
    eventManager.Subscribe<EventArgs>("B", (sender, args) =>
    {
        Console.WriteLine("Raise A");
        eventManager.RaiseAsync("A", sender, args);
    });

    eventManager.RaiseAsync<EventArgs>("A",null,null).Wait();
}
当我使用Resharper测试运行程序运行此测试时,我在输出和测试通过中看到以下结果

Raise B
Raise A
Raise B
Raise A
Raise B 

尽管如此,我希望这个测试会产生一个无限循环。你能解释一下发生了什么事吗?(但是,此测试的
sync
版本会产生无限循环。)

没有看到无限循环有三个原因

首先,您的测试不是等待事件完成。您应该将测试更改为:

[Test]
public async Task LoopTest()
{
    ...
    await eventManager.RaiseAsync<EventArgs>("A", null, null);
}

但是,还不完全清楚您实际希望发生什么,这使得很难提供正确的工作代码。如果您想要异步事件处理程序,它们可能应该是
Func
而不是
Action
,您可以使用异步lambdas订阅它们。

有三个原因使您看不到无限循环

首先,您的测试不是等待事件完成。您应该将测试更改为:

[Test]
public async Task LoopTest()
{
    ...
    await eventManager.RaiseAsync<EventArgs>("A", null, null);
}

但是,还不完全清楚您实际希望发生什么,这使得很难提供正确的工作代码。如果您想要异步事件处理程序,它们可能应该是
Func
而不是
Action
,您可以使用异步lambdas订阅它们。

调用
eventManager.RaiseAsync(“A”,null,null)对RaiseAsync的任何后续调用都将在eventhandler中发生,并触发另一个异步任务

但是,您的第一个任务现在可以完成了,因此您的调用将返回,并且方法将结束。发生这种情况时,会触发另外4个事件

如果在第一次调用后添加Sleep语句,您应该看到更多后续异步事件的处理方式:

[Test]
public void LoopTest()
{
    var eventManager = new EventManager();
    eventManager.IntroduceEvent("A",typeof(EventArgs));
    eventManager.IntroduceEvent("B", typeof(EventArgs));

    eventManager.Subscribe<EventArgs>("A", (sender, args) =>
    {
        Console.WriteLine("Raise B");
        eventManager.RaiseAsync("B", sender, args);
    });
    eventManager.Subscribe<EventArgs>("B", (sender, args) =>
    {
        Console.WriteLine("Raise A");
        eventManager.RaiseAsync("A", sender, args);
    });

    eventManager.RaiseAsync<EventArgs>("A",null,null);

    //Wait a little bit to get more async events processed
    System.Threading.Thread.Sleep(1000);
}
[测试]
公开测试()
{
var eventManager=new eventManager();
eventManager.IntroductEvent(“A”,类型为(EventArgs));
eventManager.IntroductEvent(“B”,类型为(EventArgs));
eventManager.Subscribe(“A”,(发送方,参数)=>
{
控制台。写入线(“升起B”);
eventManager.RaiseAsync(“B”,发送方,参数);
});
eventManager.Subscribe(“B”,(发送方,参数)=>
{
控制台。写线(“升起A”);
eventManager.RaiseAsync(“A”,发送方,args);
});
eventManager.RaiseAsync(“A”,null,null);
//请稍等,以处理更多异步事件
系统线程线程睡眠(1000);
}
现在,主线程将被冻结1000毫秒,允许独立的异步子任务引发和处理更多事件


在实时环境中,这将是一个无限循环。在这里,我假设测试环境在TestMethod结束后终止所有其他异步任务很简单。

在调用
eventManager.RaiseAsync(“A”,null,null)之后对RaiseAsync的任何后续调用都将在eventhandler中发生,并触发另一个异步任务

但是,您的第一个任务现在可以完成了,因此您的调用将返回,并且方法将结束。发生这种情况时,会触发另外4个事件

如果在第一次调用后添加Sleep语句,您应该看到更多后续异步事件的处理方式:

[Test]
public void LoopTest()
{
    var eventManager = new EventManager();
    eventManager.IntroduceEvent("A",typeof(EventArgs));
    eventManager.IntroduceEvent("B", typeof(EventArgs));

    eventManager.Subscribe<EventArgs>("A", (sender, args) =>
    {
        Console.WriteLine("Raise B");
        eventManager.RaiseAsync("B", sender, args);
    });
    eventManager.Subscribe<EventArgs>("B", (sender, args) =>
    {
        Console.WriteLine("Raise A");
        eventManager.RaiseAsync("A", sender, args);
    });

    eventManager.RaiseAsync<EventArgs>("A",null,null);

    //Wait a little bit to get more async events processed
    System.Threading.Thread.Sleep(1000);
}
[测试]
公开测试()
{
var eventManager=new eventManager();
eventManager.IntroductEvent(“A”,类型为(EventArgs));
eventManager.IntroductEvent(“B”,类型为(EventArgs));
eventManager.Subscribe(“A”,(发送方,参数)=>
{
控制台。写入线(“升起B”);
eventManager.RaiseAsync(“B”,发送方,参数);
});
eventManager.Subscribe(“B”,(发送方,参数)=>
{
控制台。写线(“升起A”);
eventManager.RaiseAsync(“A”,发送方,args);
});
eventManager.RaiseAsync(“A”,null,null);
//请稍等,以处理更多异步事件
系统线程线程睡眠(1000);
}
现在,主线程将被冻结1000毫秒,允许独立的异步子任务引发和处理更多事件


在实时环境中,这将是一个无限循环。在这里,我假设测试环境在TestMethod结束后终止所有其他异步任务很简单。

发布代码时,请注意格式设置。您的代码没有理由像我编辑它之前那样缩进。接下来,您的测试不会等待
RaiseAsync
的结果完成。这可能是一个等待结果的异步测试…谢谢:)很荣幸让您的代码由Jon Skeet编辑:)是的,这里发生的事情比我最初想象的要多——请看我的答案。根据您的评论等,我建议查看已有的事件聚合器。发布代码时请注意格式。您的代码没有理由像我编辑它之前那样缩进。接下来,您的测试不会等待
RaiseAsync
的结果完成。这可能是一个等待结果的异步测试…谢谢:)很荣幸让你的代码由Jon Skeet编辑:)是的,事情比我最初想象的要多-请看我的答案。根据你的评论等。我建议调查已经存在的事件聚合器。嗯。我已经按照你的建议更改了方法。测试仍然通过,但Resharper test runner表示流产。@Beatles 1692:我在底部的更改不应该改变行为,但它使它更清楚。现在还不清楚的是你想要实现什么。您应该非常仔细地考虑全局—您允许订阅哪种类型的事件处理程序(同步或异步),以及您希望
RaiseEvent
做什么。我将此事件管理器作为我们所有组件的主干,以便