Как предотвратить наследование задачи родительским заданием в контексте логического вызова - PullRequest
0 голосов
/ 27 ноября 2018

Я пытаюсь использовать AsyncLocal в качестве замены для локального хранилища Thread при использовании методов Task.Run () и Async.У меня проблема в том, что мне нужен код ниже, чтобы напечатать

from t1 t1
from t1 t1
from t2 t2
from t2 t2

Это было бы поведение при использовании локального хранилища потока, но вместо этого я получаю этот вывод.

from t1 t1
from t1 t1
from t2 t1
from t2 t1

Пример кода:

public class ClientClass {

   public static void Main() 
   {
      AsyncLocal<string> _asyncLocalString = new AsyncLocal<string>();
      var t1 = Task.Run( async () => {
          string a = _asyncLocalString.Value;
          if (a == null) {
              _asyncLocalString.Value = "t1";
          }
          a = _asyncLocalString.Value;
          Console.WriteLine("from t1 " + a);
          await Task.Delay(10);
          string b = _asyncLocalString.Value;
          Console.WriteLine("from t1 " + b);
          var t2 = Task.Run( async () => {
              string aa = _asyncLocalString.Value;
              if (aa == null) {
                  _asyncLocalString.Value = "t2";
              }
              aa = _asyncLocalString.Value;
              Console.WriteLine("from t2 " + aa);
              await Task.Delay(10);
              string bb = _asyncLocalString.Value;
              Console.WriteLine("from t2 " + bb);

          });
          await t2;
      });
      t1.Wait();
   }
} 

Ответы [ 2 ]

0 голосов
/ 29 ноября 2018

Вы можете подавить поток до вызова Task.Run и восстановить его после

public class ClientClass {

   public static void Main() 
   {
        AsyncLocal<string> _asyncLocalString = new AsyncLocal<string>();
        var t1 = Task.Run(async () =>
        {
            string a = _asyncLocalString.Value;
            if (a == null)
            {
                _asyncLocalString.Value = "t1";
            }
            a = _asyncLocalString.Value;
            Console.WriteLine("from t1 " + a);
            await Task.Delay(10);
            string b = _asyncLocalString.Value;
            Console.WriteLine("from t1 " + b);

            ExecutionContext.SuppressFlow();

            var t2 = Task.Run(async () =>
            {
                string aa = _asyncLocalString.Value;
                if (aa == null)
                {
                    _asyncLocalString.Value = "t2";
                }
                aa = _asyncLocalString.Value;
                Console.WriteLine("from t2 " + aa);
                await Task.Delay(10);
                string bb = _asyncLocalString.Value;
                Console.WriteLine("from t2 " + bb);

            });

            ExecutionContext.RestoreFlow();

            await t2;
        });
        t1.Wait();
   }
} 

Giving

from t1 t1
from t1 t1
from t2 t2
from t2 t2
0 голосов
/ 29 ноября 2018

Единственный известный мне способ - использовать ThreadPool.UnsafeQueueUserWorkItem :

public class ClientClass {

   public static void Main() 
   {
        AsyncLocal<string> _asyncLocalString = new AsyncLocal<string>();
        var t1 = Task.Run(async () =>
        {
            string a = _asyncLocalString.Value;
            if (a == null)
            {
                _asyncLocalString.Value = "t1";
            }
            a = _asyncLocalString.Value;
            Console.WriteLine("from t1 " + a);
            await Task.Delay(10);
            string b = _asyncLocalString.Value;
            Console.WriteLine("from t1 " + b);
            var tcs = new TaskCompletionSource<bool>();
            ThreadPool.UnsafeQueueUserWorkItem(async s =>
            {
                string aa = _asyncLocalString.Value;
                if (aa == null)
                {
                    _asyncLocalString.Value = "t2";
                }
                aa = _asyncLocalString.Value;
                Console.WriteLine("from t2 " + aa);
                await Task.Delay(10);
                string bb = _asyncLocalString.Value;
                Console.WriteLine("from t2 " + bb);
                ((TaskCompletionSource<bool>)s).SetResult(true);
            }, tcs);
            await tcs.Task;
        });
        t1.Wait();
   }
} 
...