Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/321.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#_System.reactive_Reactive Programming - Fatal编程技术网

C# 可观测字节数组到对象的转换

C# 可观测字节数组到对象的转换,c#,system.reactive,reactive-programming,C#,System.reactive,Reactive Programming,我第一次在一个项目中使用了Reactive,我遇到了一个性能非常重要的问题 概述: 我通过TCP套接字检索大量数据,我必须将其解析为对象并插入数据库。每封邮件都有以下签名: 其中,size是uint32(4kb),它以字节为单位描述以下有效负载的大小 问题: 我想使用反应式框架提供的功能来并行化以下步骤(见下文),以最大限度地提高性能并避免成为瓶颈。此外,我要求为实现这一点提供“最佳实践” TCP Socket ---> Observable (ArraySegment<byte&

我第一次在一个项目中使用了Reactive,我遇到了一个性能非常重要的问题

概述: 我通过TCP套接字检索大量数据,我必须将其解析为对象并插入数据库。每封邮件都有以下签名:

其中,size是uint32(4kb),它以字节为单位描述以下有效负载的大小

问题: 我想使用反应式框架提供的功能来并行化以下步骤(见下文),以最大限度地提高性能并避免成为瓶颈。此外,我要求为实现这一点提供“最佳实践”

TCP Socket ---> Observable (ArraySegment<byte>) --> Observable (Message)

提前感谢!:)

编辑:在Dimitri的评论之后,我在下面提出了一个修订的解决方案。有一行需要进行绝望的重构,但它似乎是可行的

窗口
使用重载,因此我们可以编写自定义缓冲

var hinge = new Subject<Unit>();

observableSocket
.SelectMany(i => i) // to IObservable<byte> 
.Window(() => hinge) // kinda-like-buffer
.Select(buff =>
{    
    return
        from size in buff.Buffer(SIZEOFUINT32).Select(ConvertToUINT32)
        from payload in buff.Buffer(size)
        //Refactor line below! Window must be closed somehow..
        from foo in Observable.Return(Unit.Default).Do( _ => hinge.OnNext(Unit.Default)) 
        select payload;                     
})
.SelectMany(i=>i)
.ObserveOn(ThreadPoolScheduler.Instance)
.Select(ConvertToMessage);
var铰链=新主题();
可观察小盒
.SelectMany(i=>i)//可查看
.Window(()=>铰链)//有点像缓冲区
.选择(buff=>
{    
返回
从buff.Buffer(SIZEOFUINT32)中的大小选择(ConvertToUINT32)
来自缓冲区中的有效负载(大小)
//下面的重构行!窗口必须以某种方式关闭。。
从Observable.Return(Unit.Default.Do)中的foo(=>hinge.OnNext(Unit.Default))
选择有效载荷;
})
.SelectMany(i=>i)
.ObserveOn(ThreadPoolScheduler.Instance)
。选择(ConvertToMessage);

编辑2:删除旧解决方案

这是我最后使用的解决方案。请随意评论可能的改进

    public static IObservable<DataMessage> Convert(IObservable<ArraySegment<byte>> bytes)
            {
                const int headerSize = 12; // bytes

                return bytes.Scan(
                    new
                    {
                        Leftovers = new byte[0],
                        Messages = new List<DataMessage>(),
                        Header = (Header) null
                    },
                    (saved, current) =>
                    {
                        var data = ConcatdArrays(saved.Leftovers, current.ToArray());
                        var messages = new List<DataMessage>();
                        var header = saved.Header;

                        while (true)
                        {
                            // Header
                            if (header == null && data.Count >= headerSize)
                            {
                                header = ReadHeader(ref data, headerSize);
                            }

                            // Payload
                            else if (header != null)
                            {
                                var type = header.Type;
                                var size = DataItem.Size(type);

                                if (data.Count < size) break; // Still missing data

                                // Create new message with the gathered data
                                var payload = ReadPayload(ref data, size);
                                messages.Add(new DataMessage(header, payload));
                                header = null;
                            }

                            // Can't do more with the available data - try again next round.
                            else
                            {
                                break;
                            }
                        }

                        return new
                        {
                            Leftovers = data.ToArray(),
                            Messages = messages,
                            Header = header
                        };
                    }).SelectMany(list => list.Messages);
公共静态IObservable转换(IObservable字节)
{
const int headerSize=12;//字节
返回字节。扫描(
新的
{
剩余=新字节[0],
消息=新列表(),
Header=(Header)null
},
(已保存,当前)=>
{
var data=concatdarray(saved.Leftovers,current.ToArray());
var messages=新列表();
var header=已保存的.header;
while(true)
{
//标题
if(header==null&&data.Count>=headerSize)
{
header=ReadHeader(参考数据,headerSize);
}
//有效载荷
else if(标题!=null)
{
var type=header.type;
var size=DataItem.size(类型);
if(data.Countlist.Messages);

我很好奇为什么你认为并行读取TCP套接字(流)可以提高任何性能。如果我错了,请纠正我:)我想要的是让检索逻辑在单独的“线程”中运行,并让转换逻辑并发运行,这样数据转换就不会阻塞(正在进行一些繁重的数据转换)您能提供完整的代码示例吗,因为我制作了observableSocket=Subject();//您的代码;observableSocket.OnNext(…);observableSocket.OnNext(…);而且它也不起作用。您的代码很难阅读和理解。Rx实际上允许在您选择的计划程序上运行订阅,我们不应该将任务和Rx混合使用。我们的想法是从初始序列创建一个IObservable,然后再创建res.ObserveOn(ThreadPoolScheduler.Instance)。选择(ConvertToMessage)@DmitryDovgopoly您是对的,答案并不像我说的那样完整。使用
ObserveOn
将数据转换移动到线程池是个好主意,窗口可以提供字节列表。我将为答案添加一个工作示例
var hinge = new Subject<Unit>();

observableSocket
.SelectMany(i => i) // to IObservable<byte> 
.Window(() => hinge) // kinda-like-buffer
.Select(buff =>
{    
    return
        from size in buff.Buffer(SIZEOFUINT32).Select(ConvertToUINT32)
        from payload in buff.Buffer(size)
        //Refactor line below! Window must be closed somehow..
        from foo in Observable.Return(Unit.Default).Do( _ => hinge.OnNext(Unit.Default)) 
        select payload;                     
})
.SelectMany(i=>i)
.ObserveOn(ThreadPoolScheduler.Instance)
.Select(ConvertToMessage);
    public static IObservable<DataMessage> Convert(IObservable<ArraySegment<byte>> bytes)
            {
                const int headerSize = 12; // bytes

                return bytes.Scan(
                    new
                    {
                        Leftovers = new byte[0],
                        Messages = new List<DataMessage>(),
                        Header = (Header) null
                    },
                    (saved, current) =>
                    {
                        var data = ConcatdArrays(saved.Leftovers, current.ToArray());
                        var messages = new List<DataMessage>();
                        var header = saved.Header;

                        while (true)
                        {
                            // Header
                            if (header == null && data.Count >= headerSize)
                            {
                                header = ReadHeader(ref data, headerSize);
                            }

                            // Payload
                            else if (header != null)
                            {
                                var type = header.Type;
                                var size = DataItem.Size(type);

                                if (data.Count < size) break; // Still missing data

                                // Create new message with the gathered data
                                var payload = ReadPayload(ref data, size);
                                messages.Add(new DataMessage(header, payload));
                                header = null;
                            }

                            // Can't do more with the available data - try again next round.
                            else
                            {
                                break;
                            }
                        }

                        return new
                        {
                            Leftovers = data.ToArray(),
                            Messages = messages,
                            Header = header
                        };
                    }).SelectMany(list => list.Messages);