C# 对于SendAsync到BufferBlock到Async的转换?

C# 对于SendAsync到BufferBlock到Async的转换?,c#,async-await,task-parallel-library,tpl-dataflow,parallel-for,C#,Async Await,Task Parallel Library,Tpl Dataflow,Parallel For,我正在学习关于第三方物流数据流库的知识。到目前为止,这正是我想要的 我创建了一个简单的类(如下),它执行以下函数 执行ImportPropertiesForBranch后,我转到第三方api并获取属性列表 返回xml列表并将其反序列化为属性数据数组(id、api端点、LastUpdate)。大约有400多处房产(如房屋) 然后我使用一个Parallel.Fortosendascync将属性数据放入我的propertyBufferBlock propertyBufferBlock链接到一个pro

我正在学习关于第三方物流数据流库的知识。到目前为止,这正是我想要的

我创建了一个简单的类(如下),它执行以下函数

  • 执行
    ImportPropertiesForBranch
    后,我转到第三方api并获取属性列表
  • 返回xml列表并将其反序列化为属性数据数组(id、api端点、LastUpdate)。大约有400多处房产(如房屋)
  • 然后我使用一个
    Parallel.For
    to
    sendascync
    将属性数据放入我的
    propertyBufferBlock
  • propertyBufferBlock
    链接到一个
    propertyXmlBlock
    (它本身就是一个
    TransformBlock
  • propertyXmlBlock
    然后(异步)返回API(使用属性数据中提供的API端点)并获取属性xml进行反序列化
  • 一旦xml返回并可用,我们就可以反序列化了
  • 稍后,我将添加更多的
    TransformBlock
    s以将其持久化到数据存储中
所以我的问题是,

  • 代码中是否存在任何可能带来麻烦的潜在瓶颈或区域?我知道我没有包括任何错误处理或取消(这是即将到来的)
  • 转换块中等待
    异步调用可以吗
    还是这是一个 瓶颈
  • 虽然代码可以工作,但我担心
    并行的缓冲和异步性。对于
    缓冲块
    转换块
    中的异步。我不确定这是不是最好的方法,我可能混淆了一些概念
欢迎任何指导、改进和陷阱建议

using System.Diagnostics;
using System.Threading.Tasks;
using System.Threading.Tasks.Dataflow;
using My.Interfaces;
using My.XmlService.Models;

namespace My.ImportService
{
    public class ImportService
    {

        private readonly IApiService _apiService;
        private readonly IXmlService _xmlService;
        private readonly IRepositoryService _repositoryService;

        public ImportService(IApiService apiService,
            IXmlService xmlService,
            IRepositoryService repositoryService)
        {
            _apiService = apiService;
            _xmlService = xmlService;
            _repositoryService = repositoryService;

            ConstructPipeline();
        }

        private BufferBlock<propertiesProperty> propertyBufferBlock;
        private TransformBlock<propertiesProperty, string> propertyXmlBlock;
        private TransformBlock<string, propertyType> propertyDeserializeBlock;
        private ActionBlock<propertyType> propertyCompleteBlock;

        public async Task<bool> ImportPropertiesForBranch(string branchName, int branchUrlId)
        {
            var propertyListXml = await _apiService.GetPropertyListAsync(branchUrlId);

            if (string.IsNullOrEmpty(propertyListXml))
                return false;

            var properties = _xmlService.DeserializePropertyList(propertyListXml);

            if (properties?.property == null || properties.property.Length == 0)
                return false;

            // limited to the first 20 for testing
            Parallel.For(0, 20,
                new ParallelOptions {MaxDegreeOfParallelism = 3},
                i => propertyBufferBlock.SendAsync(properties.property[i]));

            propertyBufferBlock.Complete();

            await propertyCompleteBlock.Completion;

            return true;
        }

        private void ConstructPipeline()
        {
            propertyBufferBlock = GetPropertyBuffer();
            propertyXmlBlock = GetPropertyXmlBlock();
            propertyDeserializeBlock = GetPropertyDeserializeBlock();
            propertyCompleteBlock = GetPropertyCompleteBlock();

            propertyBufferBlock.LinkTo(
                propertyXmlBlock,
                new DataflowLinkOptions {PropagateCompletion = true});

            propertyXmlBlock.LinkTo(
                propertyDeserializeBlock,
                new DataflowLinkOptions {PropagateCompletion = true});

            propertyDeserializeBlock.LinkTo(
                propertyCompleteBlock,
                new DataflowLinkOptions {PropagateCompletion = true});
        }

        private BufferBlock<propertiesProperty> GetPropertyBuffer()
        {
            return new BufferBlock<propertiesProperty>();
        }

        private TransformBlock<propertiesProperty, string> GetPropertyXmlBlock()
        {
            return new TransformBlock<propertiesProperty, string>(async propertiesProperty =>
                {
                    Debug.WriteLine($"getting xml {propertiesProperty.prop_id}");
                    var propertyXml = await _apiService.GetXmlAsStringAsync(propertiesProperty.url);
                    return propertyXml;
                },
                new ExecutionDataflowBlockOptions
                {
                    MaxDegreeOfParallelism = 1,
                    BoundedCapacity = 2
                });
        }

        private TransformBlock<string, propertyType> GetPropertyDeserializeBlock()
        {
            return new TransformBlock<string, propertyType>(xmlAsString =>
                {
                    Debug.WriteLine($"deserializing");
                    var propertyType = _xmlService.DeserializeProperty(xmlAsString);
                    return propertyType;
                },
                new ExecutionDataflowBlockOptions
                {
                    MaxDegreeOfParallelism = 1,
                    BoundedCapacity = 2
                });
        }

        private ActionBlock<propertyType> GetPropertyCompleteBlock()
        {
            return new ActionBlock<propertyType>(propertyType =>
                {
                    Debug.WriteLine($"complete {propertyType.id}");
                    Debug.WriteLine(propertyType.address.display);
                },
                new ExecutionDataflowBlockOptions
                {
                    MaxDegreeOfParallelism = 1,
                    BoundedCapacity = 2
                });
        }
    }
}
使用系统诊断;
使用System.Threading.Tasks;
使用System.Threading.Tasks.Dataflow;
使用My.Interfaces;
使用My.XmlService.Models;
名称空间My.ImportService
{
公共类导入服务
{
私有只读IApiService(apiService);
专用只读IXmlService xmlService;
专用只读IRepositoryService\u repositoryService;
公共进口服务(IApiService apiService),
IXmlService xmlService,
IRepositoryService(存储服务)
{
_apiService=apiService;
_xmlService=xmlService;
_repositoryService=repositoryService;
构造管道();
}
私有缓冲块propertyBufferBlock;
私有TransformBlock propertyXmlBlock;
私有TransformBlock PropertyBlock;
私有ActionBlock属性CompleteBlock;
公共异步任务ImportProperties ForBranch(字符串branchName,int BranchHurlId)
{
var propertyListXml=await _apiService.GetPropertyListAsync(branchUrlId);
if(string.IsNullOrEmpty(propertyListXml))
返回false;
var properties=_xmlService.DeserializePropertyList(propertyListXml);
if(properties?.property==null | | properties.property.Length==0)
返回false;
//仅限于前20个测试
对于(0,20,
新的并行选项{MaxDegreeOfParallelism=3},
i=>propertyBufferBlock.SendAsync(properties.property[i]);
propertyBufferBlock.Complete();
等待propertyCompleteBlock.完成;
返回true;
}
私有管道()
{
propertyBufferBlock=GetPropertyBuffer();
propertyXmlBlock=GetPropertyXmlBlock();
propertyDeserializeBlock=GetPropertyDeserializeBlock();
propertyCompleteBlock=GetPropertyCompleteBlock();
propertyBufferBlock.LinkTo(
propertyXmlBlock,
新的DataflowLinkOptions{PropagateCompletion=true});
propertyXmlBlock.LinkTo(
地产板块,
新的DataflowLinkOptions{PropagateCompletion=true});
propertyDeserializeBlock.LinkTo(
不动产完整区块,
新的DataflowLinkOptions{PropagateCompletion=true});
}
私有缓冲块GetPropertyBuffer()
{
返回新的缓冲块();
}
私有TransformBlock GetPropertyXmlBlock()
{
返回新的TransformBlock(异步属性Property=>
{
Debug.WriteLine($“获取xml{propertiesProperty.prop_id}”);
var propertyXml=await _apiService.GetXmlAsStringAsync(propertiesProperty.url);
返回属性xml;
},
新的ExecutionDataflowBlockOptions
{
MaxDegreeOfParallelism=1,
边界容量=2
});
}
私有TransformBlock GetPropertyDeserializeBlock()
{
返回新的TransformBlock(xmlAsString=>
{
WriteLine($“反序列化”);
var propertyType=_xmlService.DeserializeProperty(xmlAsString);
返回属性类型;
},
新的ExecutionDataflowBlockOptions
{
MaxDegreeOfParallelism=1,
边界容量=2
});
}
私有操作块GetPropertyCompleteBlock()
{
返回新的ActionBlock(propertyType=>
{
WriteLine($“complete{propertyType.id}”);
Debug.WriteLine(propertyType.address.display);
},
新的ExecutionDataflowBlockOptions
{
MaxDegreeOfParallelism=1,
边界容量=2
});
}
}
i => propertyBufferBlock.SendAsync(properties.property[i])
MaxDegreeOfParallelism = 1