Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/296.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# NetTcpBinding和异步/等待WCF阻塞_C#_Wcf_Asynchronous_Async Await_Nettcpbinding - Fatal编程技术网

C# NetTcpBinding和异步/等待WCF阻塞

C# NetTcpBinding和异步/等待WCF阻塞,c#,wcf,asynchronous,async-await,nettcpbinding,C#,Wcf,Asynchronous,Async Await,Nettcpbinding,我们正在创建用于异步操作的共享WCF通道: var channelFactory = new ChannelFactory<IWcfService>(new NetTcpBinding {TransferMode = TransferMode.Buffered}); channelFactory.Endpoint.Behaviors.Add(new DispatcherSynchronizationBehavior(true, 25)); var channel = channel

我们正在创建用于异步操作的共享WCF通道:

var channelFactory = new ChannelFactory<IWcfService>(new NetTcpBinding {TransferMode = TransferMode.Buffered});

channelFactory.Endpoint.Behaviors.Add(new DispatcherSynchronizationBehavior(true, 25));
var channel = channelFactory.CreateChannel(new EndpointAddress(new Uri("net.tcp://localhost:80/Service").AbsoluteUri + "/Test"));
然后所有3个请求同时到达服务器,然后服务器同时响应所有3个请求

但是,一旦响应到达客户端,它就会依次处理每个响应

Response
// 5 second delay
Wait completed
// Instant
Response
// 5 second delay
Wait completed
// Instant
Response
响应将在不同的线程上恢复,但每次仅运行1次

如果我们使用流而不是缓冲,我们将获得预期的行为,客户端将同时处理所有3个响应

我们已尝试使用
dispatchersynchronizationbehavior
、不同的并发模式、切换会话、
configurewait
false以及显式调用
channel.Open()
来设置最大缓冲区大小

似乎没有办法在共享会话上获得适当的并发响应

编辑 我已经添加了一个我认为正在发生的事情的图像,这个仅在缓冲模式下发生,在流模式下主线程不会阻塞

@下划线

我最近正试图解决完全相同的问题。虽然我无法确切地确定为什么
TransferMode.Buffered
会导致WCF通道上出现全局锁,直到使用它的线程被释放,但我发现了类似的问题。他们建议一种解决方法,将
RunContinuationsAsynchronously()
添加到您的等待中,即
wait频道。DoSomethingAsync().RunContinuationsAsynchronously()
其中
RunContinuationsAsynchronously()

公共静态类任务扩展
{
公共静态任务运行持续同步(此任务)
{
var tcs=new TaskCompletionSource();
任务。继续((t,o)=>
{
如果(t.IsFaulted)
{
如果(t.Exception!=null)tcs.SetException(t.Exception.InnerExceptions);
}
否则,如果(t.IsCanceled)
{
setCancelled();
}
其他的
{
tcs.SetResult(t.Result);
}
},TaskContinuationOptions.ExecuteSynchronously,TaskScheduler.Default);
返回tcs.Task;
}
公共静态任务运行持续同步(此任务)
{
var tcs=new TaskCompletionSource();
任务。继续((t,o)=>
{
如果(t.IsFaulted)
{
如果(t.Exception!=null)tcs.SetException(t.Exception.InnerExceptions);
}
否则,如果(t.IsCanceled)
{
setCancelled();
}
其他的
{
tcs.SetResult(空);
}
},TaskContinuationOptions.ExecuteSynchronously,TaskScheduler.Default);
返回tcs.Task;
}
}
它分隔了WCF的延续。显然
Task.Yield()
也有效


不过,如果能真正理解为什么会发生这种情况,那就太好了。

首先,为什么要使用阻塞
线程。Sleep(5000)
而不是非阻塞
等待任务。Delay(5000)
?第二,为什么要为异步方法使用
Task.Run
?在深入挖掘之前,您应该首先正确应用async/await模式。Thread.Sleep仅仅是为了模拟一个长阻塞操作,事实上,它需要几万行代码才能完成,这仅仅是提供MVCE的代码。如上所述,Task.Run在控制台Main方法中提供了一个可运行且易于验证的示例。是的,但是在
Task DoStuffAsync(IWcfService channel)
中这样做会在客户端阻塞线程,请参阅我的答案。
        using ((IDisposable)channel)
        {
            var task1 = Task.Run(async () => await DoStuffAsync(channel));
            var task2 = Task.Run(async () => await DoStuffAsync(channel));
            var task3 = Task.Run(async () => await DoStuffAsync(channel));

            Task.WaitAll(task1, task2, task3);
        }
    }

    public static async Task DoStuffAsync(IWcfService channel)
    {
        await channel.DoSomethingAsync();

        Console.WriteLine("Response");

        // Simulate long running CPU bound operation
        Thread.Sleep(5000);

        Console.WriteLine("Wait completed");
    }
Response
// 5 second delay
Wait completed
// Instant
Response
// 5 second delay
Wait completed
// Instant
Response
public static class TaskExtensions
{
    public static Task<T> RunContinuationsAsynchronously<T>(this Task<T> task)
    {
        var tcs = new TaskCompletionSource<T>();

        task.ContinueWith((t, o) =>
        {
            if (t.IsFaulted)
            {
                if (t.Exception != null) tcs.SetException(t.Exception.InnerExceptions);
            }
            else if (t.IsCanceled)
            {
                tcs.SetCanceled();
            }
            else
            {
                tcs.SetResult(t.Result);
            }
        }, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);

        return tcs.Task;
    }

    public static Task RunContinuationsAsynchronously(this Task task)
    {
        var tcs = new TaskCompletionSource<object>();

        task.ContinueWith((t, o) =>
        {
            if (t.IsFaulted)
            {
                if (t.Exception != null) tcs.SetException(t.Exception.InnerExceptions);
            }
            else if (t.IsCanceled)
            {
                tcs.SetCanceled();
            }
            else
            {
                tcs.SetResult(null);
            }
        }, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);

        return tcs.Task;
    }
}