简体   繁体   English

反应式Observable.Create为异步生产者而无需Task.Run

[英]Reactive Observable.Create for async producer without Task.Run

I want write function which will return items asynchronously: 我想要写函数,它将异步返回项目:

public static async Task<IEnumerable<T>> GetItems()
{
    while (await ShouldLoopAsync())
    {
        yield return await GetItemAsync();
    }
}

Of course it will not work. 当然不会。 In 1 they propose next solution: 他们在1中提出了下一个解决方案:

return Observable.Create<T>(
    observer => Task.Run(async () =>
        {
            while (await ShouldLoopAsync())
            {
                observer.OnNext(await getAsync());
            }
            observer.OnCompleted();
        }
    )
);

I don't like accepted solution from 1 because it uses Task.Run method inside Observable.Create. 我不喜欢1接受的解决方案,因为它在Observable.Create中使用Task.Run方法。 I want some solution with reactive extensions which will run on the current TaskScheduler without using other threads except existing one. 我想要一些具有反应性扩展的解决方案,该解决方案可以在当前TaskScheduler上运行,而不使用现有线程以外的其他线程。 I can write such solution in declarative way using .net events but I can't with Rx. 我可以使用.net事件以声明的方式编写此类解决方案,但不能使用Rx。

UPDATE 更新

I tried to remove Task.Run and write next test: 我试图删除Task.Run并编写下一个测试:

[TestClass]
public class ReactiveWithTaskIEnumerable
{
    [TestMethod]
    public void ReactibeShouldProcessValuesWithoutnakoplenie()
    {
        Trace.WriteLine($"Start Thread {Thread.CurrentThread.ManagedThreadId}");
        var i = GetIntsAsync()
            .Subscribe(
            onNext: p =>
            {
                Trace.WriteLine($"onNext Thread {Thread.CurrentThread.ManagedThreadId} {p}");
            },
            onCompleted: () =>
            {
                Trace.WriteLine($"onCompleted Thread {Thread.CurrentThread.ManagedThreadId}");
            },
            onError: p =>
            {
                Trace.WriteLine($"onError Thread {Thread.CurrentThread.ManagedThreadId} {p}");
                throw p;
            }
            );
        Trace.WriteLine($"Finish Thread {Thread.CurrentThread.ManagedThreadId}");

    }

    private IObservable<int> GetIntsAsync()
    {
        return Observable.Create<int>(
            observer => async () =>
            {
                Trace.WriteLine($"Produce {Thread.CurrentThread.ManagedThreadId}");
                try
                {
                    foreach (var i in Enumerable.Range(1, 10))
                    {
                        await Task.Delay(1000);
                        observer.OnNext(1);
                    }
                }
                catch (Exception e)
                {
                    observer.OnError(e);
                }
                observer.OnCompleted();
            });
    }
}

And the output is: 输出为:

Start Thread 3
Finish Thread 3

So internal task doesn't start at all. 因此内部任务根本不会启动。

After that I changed GetIntsAsync to this: 之后,我将GetIntsAsync更改为此:

    private IObservable<int> GetIntsAsync()
    {
        return Observable.Create<int>(
            observer =>
            {
                async Task Lambda()
                {
                    Trace.WriteLine($"Produce {Thread.CurrentThread.ManagedThreadId}");
                    try
                    {
                        foreach (var i in Enumerable.Range(1, 10))
                        {
                            await Task.Delay(1000);
                            observer.OnNext(1);
                        }
                    }
                    catch (Exception e)
                    {
                        observer.OnError(e);
                    }
                    observer.OnCompleted();
                }

                return Lambda();
            });
    }

And this gives next output: 这给出了下一个输出:

Debug Trace:
Start Thread 3
Produce 3
Finish Thread 3

It is close to output with Task.Run : 它与Task.Run输出Task.Run

Debug Trace: Start Thread 3 Produce 9 Finish Thread 3 调试跟踪:启动线程3产生9完成线程3

Now I need to wait until observable comes completion 现在我需要等到可观察到的完成

Have a go at NuGetting "System.Interactive" and then try this: 去NuGetting“ System.Interactive”,然后尝试以下操作:

public static IEnumerable<int> GetItems()
{
    return EnumerableEx.Create<int>(async y =>
    {
        while (await ShouldLoopAsync())
        {
            await y.Return(GetItemAsync());
        }
        await y.Break();
    });
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM