1

我在一个多层应用程序上工作,我需要通过三种方式优化一个长期运行的流程:

  1. 避免 EF 更新并发问题。
  2. 提高速度。
  3. 通知用户进度。

实际上,客户端代码使用完成所有工作的方法调用 WCF 服务(评估要更新的实体的数量查询要更新的实体更新它们,最后将它们保存回数据库)。

这个过程很长,除了过程完成后的最终结果外,什么都不会发回给用户。用户可以在等待表单前停留长达 10 分钟,而不知道发生了什么。

查询实体的数量和深度可能会变得非常大,我有时会遇到 OutOfMemoryExceptions。我不得不更改服务方法来一次处理 100 个实体更新,所以我的 DbContext 会经常刷新,不会变得太大。

我的实际问题是每次更新实体时我都无法通知用户,因为我的服务方法会在将结果返回给用户之前完成整个过程。

我阅读了有关实现双工服务的信息,但由于我必须向用户返回两个不同的回调(一个回调返回要更新的实体数量,另一个回调返回每个实体更新的结果)我必须在一个通用回调接口,它变得有点混乱(嗯,我的口味)。

有一个 WCF 服务方法来返回要评估的实体的数量,另一个 WCF 方法将返回一个简单的实体更新结果,每个实体都会被更新,这不是更好吗?我的 DBContext 将仅在单个实体更新时存在,因此它不会增长太多,我认为这很好。但是,我担心在此过程中经常会遇到 WCF 服务

你有什么想法?你有什么建议?

4

2 回答 2

0
  1. 避免 EF 更新并发问题。

    请参阅此问题/答案长时间运行的实体框架事务

  2. 提高速度。

    一些建议:

    • 尝试使用 SQL Profiler 查看正在执行的 SQL 查询,并优化 linq 查询
    • 或者尝试改进查询本身或调用存储过程。
    • 更新可以并行进行吗?不同的线程?不同的处理器?
  3. 通知用户进度。

    我建议将客户端更改为调用异步方法,或然后异步启动长时间运行的操作的方法。这将立即将控制权返回给客户端。然后由长期运行的操作来提供有关其进度的反馈。

    请参阅本文以从后台线程更新进度

    更新
    我建议的“架构”如下:

              . 服务 。. .
    ________ 。_________ _______ ____
   | | . | WCF | | 英孚 | | |
   | 客户 |---->| 服务 |->| 类 |->| 数据库 |
   |________| . |_________| |_______| |____|
              .
              . .

WCF 服务仅负责接受客户端请求,并在 EF 类中启动长时间运行的操作。客户端应向 WCF 服务发送异步请求,以便它保持控制和响应能力。EF 类负责更新数据库,您可以选择一次更新全部子集或记录。然后,EF 类可以根据需要通过 WCF 服务通知客户端它已取得的任何进展。

于 2012-10-23T19:54:25.167 回答
0

您是否考虑过将 WCF 主机添加到您的客户端?这样你就可以得到完整的双向通讯。

客户端连接到服务器并将服务器连接详细信息返回给客户端客户
端请求长时间运行操作以开始
服务器随着工作的进行向客户端 WCF 主机发送多个更新。
服务器将完成的工作发送给客户端。

这使您的客户端可以自由地做其他事情,根据您认为合适的方式使用来自服务器的消息。可能会在消息进入时更新状态区域。

您甚至可以让服务器维护一个客户端列表并向所有客户端发送更新。

--------编辑---------
当我说 WCF 主机时,我的意思是ServiceHost 它可以从 App.config 中的 XML 或直接通过代码自动创建。

var myUri = new Uri[0];
myUri[0] = new Uri("net.tcp://localhost:4000");
var someService = new SomeService(); //implements ISomeService interface
var host = new ServiceHost(someService, myUri);
var binding = new NetTcpBinding(); // need to configure this
host.AddServiceEndpoint(typeof(ISomeService), binding, "");
host.Open();

代理是我用来描述客户端用来连接服务器的术语,它是在我遇到的一个早期示例中,从那以后它就一直困扰着我。同样可以通过两种方式创建。

var binding = new NetTcpBinding(); // need to configure this
var endpointAddress = new EndpointAddress("net.tcp://localhost:4000");
var factory = new ChannelFactory<ISomeService>(binding, endpointAddress);
var proxy = factory.CreateChannel();
proxy.DoSomeWork();

因此,在典型的客户端/服务器应用程序中,您拥有

CLIENT APP 1       SERVER APP         CLIENT APP 2
proxy------------->ServiceHost<-------proxy

我的建议是您也可以使客户端成为“服务器”

CLIENT APP 1       SERVER APP         CLIENT APP 2
proxy------------->ServiceHostA<------proxy
ServiceHostB<------proxy1
                   proxy2------------>ServiceHostB

如果您这样做,您仍然可以根据需要将大型任务拆分为较小的任务(您提到了内存问题),但从事情的声音来看,它们仍然可能需要一些时间,这样进度更新仍然可以发送回客户端或如果您希望每个人都知道正在发生的事情,甚至是所有客户。不需要回调,但您仍然可以根据需要使用它们。

于 2012-10-24T02:42:36.310 回答