【问题标题】:Async tasks and data collections using Task.Run without waiting使用 Task.Run 进行异步任务和数据收集,无需等待
【发布时间】:2015-05-06 16:31:13
【问题描述】:

在 WCF 服务中,我将多个请求分派到其他 API/库,并且我不想等待这些任务完成,因此我最终使用 Task.Run 来完成异步任务无需等待完成 em>。

代码如下所示:

var someList = new List<int>();                
var i = 0;
foreach (var item in group)
{
     i++;
     var variableOne = i;
     Task.Run(async () =>
     {
              // Does the **variableOne** and variable **i** equals the latest value assigned to it, or the value at the time of calling?**
              // Can someList be prematurely garbage collected before the tasks run, because the original function containing all the code shown in the example has completed (since Task.Run is not awaited)?
              await OcrUtility.ApiOcrUpload(
              new OcrUtility.ApiOcrUploadContract()
              {
                  documentList = item.Documents
              });
      });
}

我的三个问题是:

  1. 可以在任务内容运行之前提前处置/收集一些列表(或任务内容引用的任何其他对象)吗?
  2. 任务中的变量 i 是否等于分配给它的最新值,还是调用时的值?
  3. 我习惯了 Javascript,而且我知道如果我在 javascript 中使用 setTimeout(),我需要使用某种 context-copy 技巧来保持 @ 的当前值调用时为 987654323@,因此在执行“任务”(JS 情况下的函数)时,它不会被设置为分配给 variableOne 的最新值。 我们是否需要使用 C# 进行这种复制,或者它是否带有内置的上下文复制? .Net 是否评估正在使用的变量,并在调用时创建它们的副本?

【问题讨论】:

  • I wanted to not wait for these tasks to complete 几乎可以肯定是一个设计错误。您应该仔细考虑异常是如何出现的,以及您将如何处理更新的部署。特别是,如果 WCF 由 ASP.NET 托管,这种模式尤其危险。
  • 不是真的,如果主要操作成功,我不希望客户有超时。将工作完成到最后是 Web 服务的工作,它必须自己处理它们抛出的异常。我猜你想说的是 IIS 而不是 ASP.Net?
  • @MykaEyl 名称无关紧要,但代码确实很危险。您正在尝试使用即发即弃的任务来模拟长时间运行的作业。每当应用程序池被回收或托管进程终止时,此类后台任务都可能被 IIS 终止。
  • 是的,我知道关于 IIS,它与任何其他托管系统一样,但您建议如何应对这种影响?我是不是错了,或者除非管理员或程序强制崩溃或回收,否则 IIS 不会杀死它?
  • 是的,你错了。回收不是强制的,它是一种定期启动的可靠性机制。首先,client 为什么要超时?该服务可以根据需要运行。 client 需要调整其超时值或异步等待响应。与网站不同,WCF(或任何 Web 服务)预计会运行长时间的作业。

标签: c# .net parallel-processing task-parallel-library


【解决方案1】:
  1. List&lt;T&gt; 不是一次性的,所以不,它不能被丢弃。如果您的意思是垃圾收集,那么如果您可以通过托管代码访问它们,则不会收集任何对象;这只是在处理unsafe 代码时才需要考虑的事情。

  2. 它是当前时间点的变量值,而不是关闭时变量的值。闭包关闭变量,而不是

  3. 这里的行为是一样的;闭包关闭变量,而不是值。这就是为什么您需要创建 variableOne 而不是在 lambda 中使用 i 的原因。如果你关闭了i,你会得到i的当前值,但是当你在循环内部获取那个值的副本时,永远不会改变那个变量(variableOne ),关闭变量时的值始终与调用委托时的变量值相同。

您当然可以使用以下代码对此进行简单的测试:

int i = 3;
Func<int> f = () => i;
i = 42;
Console.WriteLine(f());

如果它打印3,则意味着闭包关闭了。如果它打印42,那么它会告诉您闭包关闭了变量

【讨论】:

    【解决方案2】:

    WCF 允许您创建one-way services,其中客户端不会等待响应,因此不会超时。

    简而言之,您将方法的OperationalContract 属性的IsOneWay 属性设置为true。文档中的以下 sn-p 演示了这一点:

    [ServiceContract]
    public class OneAndTwoWay
    {
      // The client waits until a response message appears.
      [OperationContract]
      public int MethodOne (int x, out int y)
      {
        y = 34;
        return 0;
      }
    
      // The client waits until an empty response message appears.
      [OperationContract]
      public void MethodTwo (int x)
      {
        return;
      }
    
      // The client returns as soon as an outbound message
      // is queued for dispatch to the service; no response
      // message is generated or sent.
      [OperationContract(IsOneWay=true)]
      public void MethodThree (int x)
      {
        return;
      }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-02-10
      • 1970-01-01
      • 2012-11-12
      • 1970-01-01
      相关资源
      最近更新 更多