如何关联函数的输入和输出? [英] How to correlate function inputs and outputs?

查看:197
本文介绍了如何关联函数的输入和输出?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑下面的简单程序。它有一个可观察到的整数和一个函数来计算最新发布的整数是偶数还是奇数。不料,该方案的报告最近数是否为奇/偶之前报道称,号码换了。

Consider the simple program below. It has an observable of integers and a function to calculate whether the most recently published integer is even or odd. Unexpectedly, the program reports whether the most recent number is even/odd BEFORE it reports that the number changed.

static void Main(string[] args) {
    int version = 0;
    var numbers = new Subject<int>();
    IObservable<bool> isNumberEven = numbers.Select(i => i % 2 == 0);
    isNumberEven
        .Select(i => new { IsEven = i, Version = Interlocked.Increment(ref version) })
        .Subscribe(i => Console.WriteLine($"Time {i.Version} : {i.IsEven}"));
    numbers
        .Select(i => new { Number = i, Version = Interlocked.Increment(ref version) })
        .Subscribe(i => Console.WriteLine($"Time {i.Version} : {i.Number}"));
    numbers.OnNext(1);
    numbers.OnNext(2);
    numbers.OnNext(3);
    Console.ReadLine();
}



输出是:

The output is:

Time 1 : False
Time 2 : 1
Time 3 : True
Time 4 : 2
Time 5 : False
Time 6 : 3

我想换号会掀起下游效应级联和这些会在订单他们碰巧报告。交换的认购订单将交换结果报告的方式。据我所知,RX是异步的,这是可能的事情在不确定的顺序发生。如果我用.Delay(),或在我的网络功能调用我不能肯定当结果将报告。但在这种情况下,我很惊讶。

I thought that changing the number would set off a cascade of downstream effects and these would be reported IN THE ORDER THEY HAPPEN. Swapping the subscription order will swap the way results are reported. I understand that rx is asynchronous and it is possible for things to happen in non-deterministic order. If I used .Delay() or web calls in my functions I can't be sure when the results will be reported. But in this situation, I'm very surprised.

为什么这是一个大问题?我认为,这意味着,如果我想尝试功能的输入和输出的相互关联(如印刷的数字,因为他们与他们是否是偶数或奇数一起出版),我必须包括在输出结果的输入参数,就像这样:

Why is this a big deal? I think this means that if I want to try to correlate function inputs and outputs (like printing numbers as they are published along with whether they are even or odd), I MUST include the input parameters in the output results, like this:

var isNumberEven = numbers.Select(i => new {
    Number = i,
    IsEven = i % 2 == 0
});



我想我可以建立一帮小简单的功能,然后使用RX运营商来完成撰写他们复杂的计算。但是,也许我不能用RX运营商合并/加入/相关结果。我必须输入关联和输出自己,当我定义每个功能。

I thought I could build a bunch of small simple functions and then compose them using the rx operators to accomplish sophisticated calculations. But maybe I can't use the rx operators to combine/join/correlate results. I have to correlate the inputs and outputs myself when I define each function.

在某些情况下,我可以使用RX运营结果相关。如果每个输入产生一个输出,我可以压缩两个。但只要你做这样的事情油门输入它不工作了。

In some cases I can use the rx operators to correlate results. If every input generated an output, I could zip the two. But as soon as you do something like Throttle the input it doesn't work anymore.

该版本的程序似乎报告的数字是否偶数或奇数的。合理的方式

This version of the program does seem to report whether numbers are even or odd in a reasonable way.

static void Main(string[] args) {
    var numbers = new Subject<int>();
    var isNumberEven = numbers.Select(i => i % 2 == 0);
    var publishedNumbers = numbers.Publish().RefCount();
    var report =
        publishedNumbers
        .GroupJoin(
            isNumberEven,
            (_) => publishedNumbers,
            (_) => Observable.Empty<bool>(),
            (n, e) => new { Number = n, IsEven = e })
        .SelectMany(i => i.IsEven.Select(j => new { Number = i.Number, IsEven = j }));
    report.Subscribe(i => Console.WriteLine($"{i.Number} {(i.IsEven ? "even" : "odd")}"));
    numbers.OnNext(1);
    numbers.OnNext(2);
    numbers.OnNext(3);
    Console.ReadLine();
}

输出如下:

1 odd
2 even
3 odd

但我不知道这是否是机缘巧合,还是我可以依靠它。在确定性顺序发生在接收哪些操作?哪些是不可预测的?我应该是定义我的所有功能,包括在结果的输入参数?

But I don't know if this was a lucky coincidence or whether I can rely on it. What operations in Rx happen in a deterministic order? Which ones are unpredictable? Should I be defining all my functions to include the input parameters in the results?

推荐答案

您的第一个程序是完全相同的行为像我想它期望,和确定性等等。

Your first program is behaving exactly as I would expect it to, and deterministically so.

据我所知,RX是异步的,这是可能的事情,在不确定的顺序发生。

I understand that rx is asynchronous and it is possible for things to happen in non-deterministic order.

东西,如果你介绍不确定性的行为(如并发/计划)在不确定的顺序才会发生,否则接收是确定性的。

Things only happen in non-deterministic order if you introduce non-deterministic behaviour (like concurrency/Scheduling), otherwise Rx is deterministic.

有在这里打球的几个问题/误解。
1)可变外部状态 - 版本
2)使用拍摄对象的(但此示例不是一个真正的问题在所有)
3的回调是如何发出的)认识误区。

There are several issues/misconceptions at play here. 1) Mutable external state - version 2) Use of subject (but not really an issue at all in this sample) 3) Misunderstanding of how the callbacks are issued.

让我们只专注于 3)的。如果我们把你的代码,并解开其基本callsites,您可能会看到的Rx是多么简单的封面下。

Lets just focus on 3). If we take you code and unwrap it to its basic callsites, you may see how simple Rx is under the covers.

numbers.OnNext(1 ); 主题将查找它的订阅和 OnNext 他们每个人在他们认购的顺序

numbers.OnNext(1); the subject will look up it's subscriptions and OnNext each of them in the order that they subscribed.

IObservable<bool> isNumberEven = numbers.Select(i => i % 2 == 0);
isNumberEven
    .Select(i => new { IsEven = i, Version = Interlocked.Increment(ref version) })
    .Subscribe(i => Console.WriteLine($"Time {i.Version} : {i.IsEven}"));



也可以被减少到

can also be reduced to

numbers.Select(i => i % 2 == 0)
    .Select(i => new { IsEven = i, Version = Interlocked.Increment(ref version) })
    .Subscribe(i => Console.WriteLine($"Time {i.Version} : {i.IsEven}"));



一的可能的争论,随着 isNumberEven 从未使用过其他地方,你的的将其降低到这一点。

One could argue, that as isNumberEven is never used anywhere else, that you should reduce it to this.

所以我们可以看到,我们有我们的第一个订户。
和有效地将运行的代码是这样的。

So we can see we have our first subscriber. And effectively the code it would run is this

private void HandleOnNext(int i)
{
    var isEven = i % 2 == 0
    var temp = new { IsEven = isEven , Version = Interlocked.Increment(ref version) };
    Console.WriteLine($"Time {temp .Version} : {temp .IsEven}");
}

我们的第二个用户(因为 .Subscribe(法偶数订阅后的称呼),是数字用户
他的代码,可以有效地归结为

Our second subscriber (because the .Subscribe( method was called after the even number subscription), is the numbers subscriber. His code can effectively be boiled down to

private void HandleOnNext(int i)
{
    var temp = new { Number = i, Version = Interlocked.Increment(ref version) };
    Console.WriteLine($"Time {temp.Version} : {temp.Number}");
}

因此,一旦你已经完全解构了代码,你最终基本上这

So once you have fully deconstructed the code, you end up with basically this

void Main()
{
    int version = 0;

    //numbers.OnNext(1);
    ProcessEven(1, ref version);
    ProcessNumber(1, ref version);
    //numbers.OnNext(2);
    ProcessEven(2, ref version);
    ProcessNumber(2, ref version);
    //numbers.OnNext(3);
    ProcessEven(3, ref version);
    ProcessNumber(3, ref version);
}

// Define other methods and classes here
private void ProcessEven(int i, ref int version)
{
    var isEven = i % 2 == 0;
    var temp = new { IsEven = isEven, Version = Interlocked.Increment(ref version) };
    Console.WriteLine($"Time {temp.Version} : {temp.IsEven}");
}
private void ProcessNumber(int i, ref int version)
{
    var temp = new { Number = i, Version = Interlocked.Increment(ref version) };
    Console.WriteLine($"Time {temp.Version} : {temp.Number}");
}



一旦所有的回调和订阅具体化,那么你就可以看出这是没有神奇的发生,一切都是确定的。

Once all the callbacks and subscriptions are reified, then you can see that this is no magic happening and everything is deterministic.

我应该定义我的所有功能,包括在结果的输入参数?

Should I be defining all my functions to include the input parameters in the results?

要回答你的问题(我毫不犹豫地这样做给你接收的误解),你只需要这么做时,结果序列的顺序将是非确定性的。
这样的一个例子是,如果你发出多个网页请求一次。
你不能肯定他们会在所有你送的顺序作出回应。
但是你可以强制这些场景回线与运营商的如的毗连

To answer your question (which I hesitate to do so given your misunderstanding of Rx), you only need to do so when the order of the result sequence will be non deterministic. An example of this might be if you issued multiple web-requests at once. You can not be sure that they will all respond in the order you sent them. However you can force these scenarios back into line with the usage of operators like Concat

这篇关于如何关联函数的输入和输出?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆