gpt4 book ai didi

c# - 如何在MVVM中组合异步和非异步服务?

转载 作者:太空宇宙 更新时间:2023-11-03 22:56:54 24 4
gpt4 key购买 nike

设想
在基于MVVMLight的应用程序中,我使用几个 View 和服务来进行一些工作时间计算。除其他外,还有以下服务...

  • DataService :顾名思义,用于从数据库中获取数据。由于本质上是I/O操作,因此这些方法正在使用async/await。
  • 契约(Contract):这是一个受CPU约束的服务,它实际计算工作时间(例如,给定日,周,月,...)

  • 现在,让我们看一下以下方法(位于“契约(Contract)”服务中):
    public TimeSpan GetWorkTimeForDay(Date date)
    {
    // Check if that result was already calculated before and is still
    // valid. In this case, load it and return it
    if (ContractCalculationCacheResults.Contains(date))
    return ContractCalculationCacheResults.Get(date);

    var finalWorkTime = TimeSpan.Zero;

    // Get the work day from the database in a synchronous fashion
    var workDay = DataService.GetWorkDay(date);

    // if there is a work day in the database then finally calculate the work time
    if (workDay != null)
    finalWorkTime = GetWorkTimeForDay(workDay);

    // cache the result
    ContractCalculationCacheResults.Put(date, finalWorkTime);

    // return the final result
    return finalWorkTime;
    }
    此方法位于 Contract服务中。它具有对 DataService的依赖关系,以获取计算所需的数据。
    如您所见, DataService.GetWorkDay()目前处于同步状态。这是相当长时间以来访问数据库的方式。现在,在将应用程序从WP8 Silverlight移植到UWP时,我想清理代码并更改数据服务,以便它仅提供 async方法而不是同步方法。但是现在,我正在努力将两个实际上是分开的服务组合在一起,其中一种性质是同步的,而另一种性质是异步的。
    问题
    我需要更新方法 GetWorkTimeForDay()(以及许多其他看起来相似的方法)以使用新的 DataService.GetWorkDayAsync()方法,顾名思义,该方法定义如下:
    public async Task<WorkDay> GetWorkDayAsync(Date dateKey)
    但是,这导致了许多悬而未决的问题,因为 GetWorkTimeForDay突然也应该成为 async方法,即使其性质受CPU限制。因此,这没有任何意义。
    可能的解决方案
    1.使 GetWorkTimeForDay为异步方法
    结果将是这样的:
    public async Task<TimeSpan> GetWorkTimeForDay(Date date)
    {
    ...

    // Get the work day from the database in a synchronous fashion
    var workDay = await DataService.GetWorkDayAsync(date);

    ...
    }
    虽然这看起来很容易,但对其余代码有很多影响。仅仅因为在所有调用 GetWorkTimeForDay的地方,我都必须更改代码,因为此方法现在是 async。我将不得不为其添加 await,因此可能还需要更改调用方法...等等。但是有时候,并不需要仅仅因为它已经在单独的线程或后台任务中运行而异步调用 GetWorkTimeForDay()。更不用说到目前为止存在的所有单元测试了。因此,在某些情况下,它不会阻止UI。
    此外,突然之间,CPU限制的计算变得异步了,这不是它应该如何工作的(至少如果我正确地理解了Stephen Cleary的 this帖子(和其他内容))。
    2.分开服务
    因此,我想到的下一个解决方案是分离服务。换句话说,没有一项服务依赖于另一项。这将更改 GetWorkTimeForDay()的签名,如下所示:
    public TimeSpan GetWorkTimeForDay(WorkDay workDay, Date date)
    {
    var finalWorkTime = TimeSpan.Zero;

    if (workDay != null)
    finalWorkTime = GetWorkTimeForDay(workDay);

    return finalWorkTime;
    }
    然后,调用方法将类似于以下内容:
    public async void Caller(Date date)
    {
    ...

    if (ContractCalculationCacheResults.Contains(date))
    return ContractCalculationCacheResults.Get(date);

    var workDay = await DataService.GetWorkDay(date);
    var workTime = Contract.GetWorkTimeForDay(workDay, date);

    ContractCalculationCacheResults.Put(date, workTime);

    ...
    }
    与其他解决方案一样,缺点是所有调用者方法都必须更新(及其调用者,...),尽管有时这不是必需的。此外,还将添加许多用于缓存和数据库访问的冗余代码。
    从MVVM的角度来看,另一个缺点可能是突然将数据提供给了契约(Contract)服务。因此,我不会再使用DI了,因为有充分的理由,DI或多或少违反了规则。 (在我这里,关于如何正确地将服务注入(inject)服务中弹出了问题)
    最后但并非最不重要的一点是,我也必须从 GetWorkTimeForDay方法中删除缓存。只有当结果之前没有被缓存时,我才会要求数据库获取工作日,然后再进行计算。
    3.?
    ...
    实际问题
    在基于MVVM的项目中将 async服务与非 async服务结合在一起的最佳设计是什么?
    我想使实际计算保持同步,因为它们受CPU限制。我想保持数据访问异步,因为它们不受CPU限制,但可能需要一些时间。
    所以这篇文章不是关于如何等待 await/Task/...结果的技术解决方案。这更多是关于MVVM,注入(inject)其他服务的服务,同步和异步服务组合的体系结构问题。

    最佳答案

    Furthermore, suddenly the CPU bound calculations become asynchronous which is not how it should work...



    原因很简单:人们看到异步方法时,通常会认为该方法将异步执行,因此不会阻塞当前线程。

    您的方法将如下所示:
    //Start...             (On current thread)
    //Access the database (On IO Thread, freeing up the current thread)
    //Return to current thread
    //Do the calculations (On the current thread)

    人们可能不会想到的是调用线程上的工作负载。

    我在这里使用@ kevin-gosse:只需将其更改为异步方法,因为它仍然具有IO绑定(bind)部分。如果您希望其他人调用该方法,请确保也记录具有CPU密集部分的文档。

    Stephen Cleary有一些很好的例子 on his blog

    您的第二种解决方案方法也完全有效。如果您仅将“契约(Contract)”视为计算引擎,那绝对不应该在意数据的来源。您仍然有一个分离的,可测试的类。

    关于c# - 如何在MVVM中组合异步和非异步服务?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44962494/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com