嵌套的Observable在Wait()上挂起

时间:2017-09-02 17:34:47

标签: c# async-await console-application observable system.reactive

在C#控制台应用程序中,使用System.Reactive.Linq,我试图创建一个observable,其中每个项目是另一个observable进行某些处理的字符串结果。 我使用字符串和字符创建了一个简单的repro。 警告,此示例完全是CONTRIVED,重点是嵌套的.Wait()挂起。

L.Icon

同样,这不是我如何找到许多文件名的后缀。 问题是如何生成一个Observable of strings,其中字符串是从一个完整的observable计算的。

如果我拿出这个代码并单独运行它就可以了。

Syntax error in SQL statement "ALTER USER   SET PASSWORD[*] 'newpassword'"; expected "SET, RENAME, ADMIN"; SQL statement:
ALTER USER   SET PASSWORD 'newpassword' [42001-195] 42001/42001

异步方法上有嵌套的Wait(),我不明白。

如何编写嵌套的异步observable,我可以生成一个简单的字符串数组?

由于

-John

3 个答案:

答案 0 :(得分:5)

您的代码阻塞的原因是您使用ToObservable()而未指定调度程序。在这种情况下,它将使用CurrentThreadScheduler

所以files observable首先使用当前线程发出OnNext() [A](发送"file1.doxc")。在OnNext()返回之前,它无法继续迭代。但是,内部fn可观察 还使用ToObservable()Wait()阻止,直到fn完成 - 它将排队第一个OnNext() (将"f")发送到当前线程调度程序,但它永远无法发送它,因为现在第一个OnNext() [A]永远不会返回。

两个简单的修复:

要么像这样更改files observable:

IObservable<string> files = fileNames.ToObservable(NewThreadScheduler.Default);

或者,避免使用内部Wait()SelectMany(这绝对是更惯用的Rx):

string[] extensions = files.SelectMany(fn =>
{
    return fn.ToObservable()
             .TakeLast(4)
             .ToArray()
             .Select(x => new string(x));
})
.ToArray()
.Wait();

// display results etc.

每种方法都有完全不同的执行语义 - 第一种方法将像嵌套循环一样运行,每个内部observable在下一次外部迭代之前完成。由于删除了Wait()的阻塞行为,因此第二个将更加交错。如果您使用我编写的Spy方法并在ToObservable()次调用后附加它,您会非常清楚地看到此行为。

答案 1 :(得分:1)

Wait是一种阻止调用,它与Rx不能很好地混合。我不确定嵌套的失败原因。

假设有异步功能,则可以:

IObservable<string> files = fileNames.ToObservable();
string[] extensions = await files.SelectMany(async fn =>
{
    var extension = await fn.ToObservable()
    .TakeLast(4)
    .ToArray();
        return new string(extension);
})
.ToArray();

答案 2 :(得分:1)

詹姆斯已经解决了这个问题,但我建议你的代码完成这样做:

aspect > 1

现在,它仍然有一个 string[] fileNames = { "file1.doxc", "file2.xlsx", "file3.pptx" }; string[] extensions = ( from fn in fileNames.ToObservable() from extension in fn.ToObservable().TakeLast(4).ToArray() select new string(extension) ) .ToArray() .Wait(); 。理想情况下,你会做这样的事情:

.Wait()

你应该避免所有等待。