.net 如何使用反应式扩展(Rx)为慢用户排队,并提供取消支持

.net 如何使用反应式扩展(Rx)为慢用户排队,并提供取消支持,.net,system.reactive,reactive-programming,.net,System.reactive,Reactive Programming,首先是一些背景知识,我编写了一个名为(在github.com上)的开源.NET库,它使用FileSystemWatcher复制两个目录之间的所有文件更改 我已经编写了一个类,它实现了IObservable(用于包装实际的文件系统观察程序)。创建、修改或删除文件或目录时,将使用响应式扩展名通过主题发布更改 然后,我使用下面的订阅订阅这个可观察的 return observable .Buffer(() => observable.Throttle(TimeSpan.Fr

首先是一些背景知识,我编写了一个名为(在github.com上)的开源.NET库,它使用
FileSystemWatcher
复制两个目录之间的所有文件更改

我已经编写了一个类,它实现了
IObservable
(用于包装实际的
文件系统观察程序
)。创建、修改或删除文件或目录时,将使用响应式扩展名通过
主题发布更改

然后,我使用下面的订阅订阅这个可观察的

 return observable
          .Buffer(() => observable.Throttle(TimeSpan.FromSeconds(2)).Timeout(TimeSpan.FromMinutes(1)))     
          .PrioritizeFileSystemChanges()           
          .SelectMany(x => x);
缓冲更改,直到至少有2秒的时间段没有任何更改,最长为1分钟。这是因为在删除目录时,
FileSystemWatcher
会通知所有包含的文件和目录。我们可以通过接受目录中包含的更改并简单地删除订阅服务器中的父项来优化行为。这由
priorityfilesystemchanges
过滤器处理。它还允许我们忽略在缓冲区窗口中创建并随后删除的文件,从而再次减少目标上的IO操作

这是可行的,尽管目前的方式很幼稚,不支持失败/重试

然而,我的问题是,这个可观察对象的订户可能需要合理的时间来处理每个更改。例如,将大文件复制到速度较慢的文件系统。当当前正在复制的同一文件发生新的文件系统更改时,我如何处理中止正在进行的操作。或者,如果文件包含在缓冲列表中但未完成,如何删除或排除该文件

我假设需要对原始observable进行另一次订阅,但我不确定如何最好地共享状态或修改挂起的任务?更改必须按照接收顺序进行处理,这表示队列。但是,新的文件系统更改可能会应用于需要取消或删除的排队操作。队列不是为无序删除而设计的

例如,如果我们当前正在复制文件
Foo\Bar.txt
,并且
Foo
目录被删除。然后,必须取消目录和所有子目录的任何正在进行或挂起的更改。这是任务并行库的一个用例,还是我可以采取一些被动的方法


任何github拉取请求也将被友好接收

您似乎有几个目标/问题:

  • 删除由于以后的更改而不再需要的早期更改。链接列表可能非常适合这种情况。它为一般队列使用和良好的项目删除性能提供了良好的性能
  • 取消由于以后的更改而不再需要的正在进行的操作。这还包括需要重新启动的操作。这将要求您找到一个允许您取消正在进行的操作的库。System.IO类不提供这种取消功能,因此您需要找到库或自行滚动
  • 这是任务并行库的一个用例,还是我可以采取一些被动的方法?你的措辞让我感到好像这里有一个或另一个选择,但没有理由你不能把两者混合在一起。文件更改的可观察性是一个良好的起点(RX)。正在进行的操作可能会被实现为采用
    取消令牌
    并返回
    任务
    (TPL)的方法
  • 这里缺少的一步似乎是如何从更改的“队列”转到实际工作。基本上,订阅必须(快速)将更改排队,并启动(慢速、异步)方法(如果尚未运行),该方法“递归”处理队列;比如:

    “更改是您返回的可观察更改
    'toProcess是更改的“队列”
    '处理器保存有关正在进行的操作的信息和任务
    更改。订阅(Sub(c)
    UpdateQueueWithChange(c、TopProcess、processor)
    如果processor.Task.IsCompleted,则
    ProcessNextChange(处理器,TopProcess)
    如果结束
    末端接头)
    
    ProcessNextChange
    是一种方法,它将获取队列中的下一个更改,启动操作,将操作任务的回调设置为重新调用ProcessNextChange。如果没有留下任何更改,
    处理器
    应获得一个已完成的任务,该任务不会重新调用ProcessNextChange

    UpdateQueueWithChange
    将需要更新“队列”并在必要时取消正在进行的操作,这将触发调用
    ProcessNextChange
    ,因为任务完成将启动下一个操作

    如果您想在取消对可观察到的更改的订阅时取消操作,我建议将订阅一次性放入一个
    CompositeDisposable
    以及一个
    SerialDisposable
    中,该
    SerialDisposable将存储一个
    CancellationDispoable
    (由
    ProcessNextChange
    更新,并额外存储在
    processor
    中),这是操作方法所需的
    取消令牌的来源。
    ProcessNextChange将在启动操作之前检查SerialDisposable是否已被处理。CompositeDisposable将是您存储在某个位置以结束整个操作的内容

    CompositeDisposable'这是您的应用程序保留的内容
    |-IDisposable从订阅到可观察到的更改
    |-一次性连载
    |-.一次性属性=取消一次性
    '每次调用ProcessNextChange时都会更改
    
    谢谢您的建议,我喜欢您使用链表排队的想法