简体   繁体   中英

Async tasks and data collections using Task.Run without waiting

In a WCF service I am dispatching multiple requests to other API/Libraries and I wanted to not wait for these tasks to complete, so I ended up using Task.Run to complete asynchronous tasks without waiting for completion .

The code looks like this:

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
              });
      });
}

My three questions are:

  1. Can someList (or any other object referenced by the Task content) be prematurely disposed/garbage collected before the tasks content run?
  2. Does the variable i inside the task equals the latest value assigned to it, or the value at the time of calling?
  3. I'm used to Javascript, and I know that if I do use setTimeout() in javascript I need to use some kind of context-copy trick in order to keep the current value of variableOne at the time of calling, so it does not get set as the latest value assigned to variableOne when the "task" (function in the case of JS) is being executed. Do we need to do that kind of copy with C# or does it come with built-in context-copy? Does .Net evaluates which variables are being used, and create a copy of them at the time of calling?
  1. List<T> is not disposable, so no, it cannot be disposed. If you meant garbage collected, no objects will ever be collected if you can ever access them through managed code; this is only ever something to even thing about when dealing with unsafe code.

  2. It has the value of the variable at the current point in time, not the value of the variable when it was closed over. Closures close over variables , not values .

  3. The behavior is the same here; closures close over variables, not values. This is why you needed to create variableOne instead of using i in the lambda. If you closed over i you'd get the current value of i , but as you're taking a copy of that value inside the loop, and never mutating that variable ( variableOne ), the value of the variable when you close over it is always the same as the value of the variable when the delegate is invoked.

You can of course trivially test this using the following code:

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

If it prints 3 , then it means closures close over values . If it prints 42 then it tells you that closures close over variables .

WCF allows you to create one-way services , where the client doesn't wait for a response so it doesn't time out.

In short, you set the IsOneWay property of your method's OperationalContract attribute to true . The following snippet from the docs demonstrates this:

[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;
  }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM