如何异步执行WhenAnyValue委托?

3
我有这段代码,每当另一个属性更改时,它会生成一个“计算”或“输出”属性。派生属性生成正确,但由于 CreateBlurImage 执行时间较长,因此 UI 在其运行时会被冻结。
如何以异步方式实现相同的最终结果?
编辑:这是经过@Shane建议后我代码的当前版本,但UI仍然会在所有处理完成之前保持冻结。请注意,如果相关联的更新很多,那么可能会有所影响:
    public ColetaIsis Model { get; private set; }

    public string NomePaciente { get { return Model?.NomePaciente; } }
    public DateTime DataRealização { get { return Model.DataRealização; } }



    public BitmapSource Listras
    {
        get { return _listras; }
        set { this.RaiseAndSetIfChanged(ref _listras, value); }
    }
    BitmapSource _listras;


    public double[,] Grayscale { get { return _grayscale.Value; } }
    readonly ObservableAsPropertyHelper<double[,]> _grayscale;

    public double[,] BlurMenor { get { return _blurMenor.Value; } }
    readonly ObservableAsPropertyHelper<double[,]> _blurMenor;

    public double[,] BlurMaior { get { return _blurMaior.Value; } }
    readonly ObservableAsPropertyHelper<double[,]> _blurMaior;

    public double[,] Diferença { get { return _diferença.Value; } }
    readonly ObservableAsPropertyHelper<double[,]> _diferença;


    public BitmapSource FiltradaMenor { get { return _filtradaMenor?.Value; } }
    readonly ObservableAsPropertyHelper<BitmapSource> _filtradaMenor;

    public BitmapSource FiltradaMaior { get { return _filtradaMaior?.Value; } }
    readonly ObservableAsPropertyHelper<BitmapSource> _filtradaMaior;

    public BitmapSource ImagemDiferença { get { return _imagemDiferença?.Value; } }
    readonly ObservableAsPropertyHelper<BitmapSource> _imagemDiferença;


    public IEnumerable<ScatterPoint> Picos => _picos;
    IEnumerable<ScatterPoint> _picos;








    // CONSTRUTOR
    public ColetaIsisViewModel(ColetaIsis model) 
    {
        this.WhenAnyValue(x => x.Listras)
            .Where(item => item != null)
            .ObserveOn(RxApp.TaskpoolScheduler)
            .Select(im => GetArray.FromChannels(im, 0, 1))
            //.ObserveOn(RxApp.MainThreadScheduler)
            .ToProperty(this, x => x.Grayscale, out _grayscale, scheduler:RxApp.MainThreadScheduler);

        this.WhenAnyValue(x => x.Grayscale)
            .Where(item => item != null)
            .ObserveOn(RxApp.TaskpoolScheduler)
            .Select(ar => Gaussian.GaussianConvolution(ar, 1.5))
            //.ObserveOn(RxApp.MainThreadScheduler)
            .ToProperty(this, x => x.BlurMenor, out _blurMenor, scheduler: RxApp.MainThreadScheduler);

        this.WhenAnyValue(x => x.BlurMenor)
            .Where(item => item != null)
            .ObserveOn(RxApp.TaskpoolScheduler)
            .Select(ar => Gaussian.VerticalGaussianConvolution(ar, 5))
            //.ObserveOn(RxApp.MainThreadScheduler)
            .ToProperty(this, x => x.BlurMaior, out _blurMaior, scheduler: RxApp.MainThreadScheduler);

        this.WhenAnyValue(x => x.BlurMenor, x => x.BlurMaior)
            .Where(tuple => tuple.Item1 != null && tuple.Item2 != null)
            .ObserveOn(RxApp.TaskpoolScheduler)
            .Select(tuple => ArrayOperations.Diferença(tuple.Item1, tuple.Item2))
            //.ObserveOn(RxApp.MainThreadScheduler)
            .ToProperty(this, x => x.Diferença, out _diferença, scheduler: RxApp.MainThreadScheduler);



        this.WhenAnyValue(x => x.BlurMenor)
            .Where(item => item != null)
            .ObserveOn(RxApp.TaskpoolScheduler)
            .Select(ar => { ConversorImagem.Converter(ar, out BitmapSource im); return im; })
            //.ObserveOn(RxApp.MainThreadScheduler)
            .ToProperty(this, x => x.FiltradaMenor, out _filtradaMenor, scheduler: RxApp.MainThreadScheduler);

        this.WhenAnyValue(x => x.BlurMaior)
            .Where(item => item != null)
            .ObserveOn(RxApp.TaskpoolScheduler)
            .Select(ar => { ConversorImagem.Converter(ar, out BitmapSource im); return im; })
            //.ObserveOn(RxApp.MainThreadScheduler)
            .ToProperty(this, x => x.FiltradaMaior, out _filtradaMaior, scheduler: RxApp.MainThreadScheduler);

        this.WhenAnyValue(x => x.Diferença)
            .Where(item => item != null)
            .ObserveOn(RxApp.TaskpoolScheduler)
            .Select(ar => { ConversorImagem.Converter(ar, out BitmapSource im); return im; })
            //.ObserveOn(RxApp.MainThreadScheduler)
            .ToProperty(this, x => x.ImagemDiferença, out _imagemDiferença, scheduler: RxApp.MainThreadScheduler);


        Model = model;

        Listras = Model.Listras;  // fires up the initial cascading updates
    }
1个回答

3
这些方法有哪些可行?这样一来,CreateBlurImage部分就可以在UIThread之外完成。
public MyClass()
{
    this.WhenAnyValue(x => x.StripedImage)
        .ObserveOn(RxApp.TaskpoolScheduler)
        .Select(im => CreateBlurImage(im))
        .ObserveOn(RxApp.MainThreadScheduler)
        .ToProperty(this, x => x.Filtered, out _filtered);
}

我相信在ToProperty上指定调度程序与上述方法是相同的。
public MyClass()
{
    this.WhenAnyValue(x => x.StripedImage)
        .ObserveOn(RxApp.TaskpoolScheduler)
        .Select(im => CreateBlurImage(im))
        .ToProperty(this, x => x.Filtered, out _filtered, scheduler:RxApp.MainThreadScheduler);
}

如果你在 CreateBlurImage 中设置了断点,你能验证你是否在 UI 线程上吗? - Shane Neuville
我按照你所说的做法打开了VS的“Threads”窗口,出现标记的线程是MainThread。不过我不知道这是否是所期望的。 - heltonbiker
好的,我使用了仅ObserveOn版本(分别使用两个调度程序),现在方法在工作线程内被调用,但UI仍然感觉冻结,直到所有操作完成... :o( - heltonbiker
有点难说。一个猜测可能是来回调度太多了?每个属性更改都在 UI 线程上发生,然后下一组工作进入 TaskPool,然后返回到 UI,再返回到 TaskPool 等等...如果它们只是一些 getter 和 setter,然后当 "Listras" 更改时,立即在后台线程中处理所有内容,然后设置所有属性,我会很好奇它会如何运作。无论如何,我会删除所有内容,然后慢慢构建它,以隔离到底是什么导致了冻结。也许只是 wpf 在渲染那些位图方面表现得很奇怪? - Shane Neuville
1
如果“StripedImage”变化比“CreateBlurImage”处理得更快,那么您将会饱和线程池,整个系统会变慢。您可以尝试限制对CreateBlurImage的调用次数,采用节流或抽样的方式来解决这个问题。 - bradgonesurfing
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接