Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/24.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# WCF双工内的TPL数据流块_C#_.net_Wcf_Task Parallel Library_Tpl Dataflow - Fatal编程技术网

C# WCF双工内的TPL数据流块

C# WCF双工内的TPL数据流块,c#,.net,wcf,task-parallel-library,tpl-dataflow,C#,.net,Wcf,Task Parallel Library,Tpl Dataflow,我是新来的作家,所以,请容忍我 我有一个WCF服务和双工服务合同。此服务契约有一个假定要进行长时间数据处理的操作联系人。我必须将并发数据处理的数量限制在最多3个。我的问题是,在数据处理之后,我需要返回到同一个服务实例上下文,以便通过数据处理结果回调发起程序端点。我需要提到的是,由于各种原因,我只能使用TPL数据流和WCF双工 这里是我到目前为止所写内容的演示 在控制台库中,我模拟WCF调用 class Program { static void Main(string[] args)

我是新来的作家,所以,请容忍我

我有一个WCF服务和双工服务合同。此服务契约有一个假定要进行长时间数据处理的操作联系人。我必须将并发数据处理的数量限制在最多3个。我的问题是,在数据处理之后,我需要返回到同一个服务实例上下文,以便通过数据处理结果回调发起程序端点。我需要提到的是,由于各种原因,我只能使用TPL数据流和WCF双工

这里是我到目前为止所写内容的演示

在控制台库中,我模拟WCF调用

class Program
{
    static void Main(string[] args)
    {
        // simulate service calls

        Enumerable.Range(0, 5).ToList().ForEach(x =>
        {
            new System.Threading.Thread(new ThreadStart(async () =>
            {
                var service = new Service();
                await service.Inc(x);
            })).Start();
        });
    }
}
下面是假定的WCF服务

// service contract
public class Service
{
    static TransformBlock<Message<int>, Message<int>> transformBlock;

    static Service()
    {
        transformBlock = new TransformBlock<Message<int>, Message<int>>(x => Inc(x), new ExecutionDataflowBlockOptions
        {
            MaxDegreeOfParallelism = 3
        });
    }

    static Message<int> Inc(Message<int> input)
    {
        System.Threading.Thread.Sleep(100);

        return new Message<int> { Token = input.Token, Data = input.Data + 1 };
    }

    // operation contract
    public async Task Inc(int id)
    {
        var token = Guid.NewGuid().ToString();

        transformBlock.Post(new Message<int> { Token = token, Data = id });

        while (await transformBlock.OutputAvailableAsync())
        {
            Message<int> message;
            if (transformBlock.TryReceive(m => m.Token == token, out message))
            {
                // do further processing using initiator service instance members
                // something like Callback.IncResult(m.Data);
                break;
            }
        }
    }
}

public class Message<T>
{
    public string Token { get; set; }

    public T Data { get; set; }
}
//服务合同
公务舱服务
{
静态变换块变换块;
静态服务()
{
transformBlock=新的transformBlock(x=>Inc(x),新的ExecutionDataflowBlockOptions
{
MaxDegreeOfParallelism=3
});
}
静态消息公司(消息输入)
{
系统线程线程睡眠(100);
返回新消息{Token=input.Token,Data=input.Data+1};
}
//经营合同
公共异步任务公司(int id)
{
var-token=Guid.NewGuid().ToString();
Post(新消息{Token=Token,Data=id});
while(等待transformBlock.OutputAvailableAsync())
{
信息;
if(transformBlock.TryReceive(m=>m.Token==Token,out消息))
{
//使用启动器服务实例成员执行进一步处理
//类似Callback.IncResult(m.Data)的东西;
打破
}
}
}
}
公共类消息
{
公共字符串标记{get;set;}
公共T数据{get;set;}
}
操作契约实际上不需要异步,但我需要OutputAvailableAsync通知

这是一个好方法还是有更好的解决方案


提前谢谢。

首先,我认为你不应该像现在这样使用代币。在进程之间通信时,唯一标识符非常有用。但是当您在单个进程中时,只需使用引用相等

为了回答你的问题,我认为(某种)繁忙循环不是一个好主意

异步节流的一个更简单的解决方案是使用。比如:

static readonly SemaphoreSlim Semaphore = new SemaphoreSlim(3);

// operation contract
public async Task Inc(int id)
{
    await Semaphore.WaitAsync();

    try
    {
        Thread.Sleep(100);
        var result = id + 1;
        // do further processing using initiator service instance members
        // something like Callback.IncResult(result);
    }
    finally
    {
        Semaphore.Release();
    }
}
如果您真的想(或必须)使用数据流,您可以使用数据流在操作和块之间进行同步。操作方法将等待
TaskCompletionSource
Task
,块将在完成该消息的计算时设置它:

private static readonly ActionBlock<Message<int>> Block =
    new ActionBlock<Message<int>>(
        x => Inc(x),
        new ExecutionDataflowBlockOptions
        {
            MaxDegreeOfParallelism = 3
        });

static void Inc(Message<int> input)
{
    Thread.Sleep(100);

    input.TCS.SetResult(input.Data + 1);
}

// operation contract
public async Task Inc(int id)
{
    var tcs = new TaskCompletionSource<int>();

    Block.Post(new Message<int> { TCS = tcs, Data = id });

    int result = await tcs.Task;
    // do further processing using initiator service instance members
    // something like Callback.IncResult(result);
}
私有静态只读操作块=
新动作块(
x=>Inc(x),
新的ExecutionDataflowBlockOptions
{
MaxDegreeOfParallelism=3
});
静态void Inc(消息输入)
{
睡眠(100);
input.TCS.SetResult(input.Data+1);
}
//经营合同
公共异步任务公司(int id)
{
var tcs=new TaskCompletionSource();
Block.Post(新消息{TCS=TCS,Data=id});
int result=等待tcs.Task;
//使用启动器服务实例成员执行进一步处理
//类似Callback.IncResult(result)的东西;
}

“我被限制在第三方物流数据流”你是什么意思?您必须使用数据流吗?为什么?这没有多大意义。我对数据处理的要求是确保并发性,但限制并行性。TPL数据流块似乎是一个不错的选择,而且它们是由技术要求而不是PLinq或其他东西强加的。如果这真的是您使用数据流的全部目的,那么我认为这是一个过分的选择。您可以使用更简单的代码实现相同的效果(参见我的答案)。此外,我也不确定双工服务是否是这里的正确选择。客户机和服务器都可以是异步的,即使没有异步,我被告知数据流可能会演变成一个块链,在这种情况下,我应该传播TCS。不过信号灯看起来很优雅。关于复式公寓,我完全同意。非常感谢。