【问题标题】:Can Task.Result always be replaced with await?Task.Result 总是可以替换为 await 吗?
【发布时间】:2022-02-07 23:35:06
【问题描述】:

为了学习 Await/Async(并拥有一个我可以在工作中用于一些奇怪项目的工具),我制作了一个对象,它将对其公共方法的调用编组到一个特定的线程中以在那里运行。本质上,每个公共异步方法在调用时都会根据目标检查其当前线程。如果线程匹配,它将正常运行其代码。如果不匹配,它会将其输入关闭到一个 lambda 中,然后将其存储在由目标线程维护的队列中。这是我的原型,只有一个公共方法DoThing

public class ThreadedObject
    {
        private Thread thread;
        private ConcurrentQueue<Task> concurrentQ = new();
        public ThreadedObject()
        {
            thread = new(() => RunThread());
            thread.IsBackground = true;
            thread.Name = "ThreadedObjectRunner";
            thread.Start();
        }
        private bool IsInWorkerThread()
        {
            return Thread.CurrentThread == thread;
        }
        private void RunThread()
        {
            while (true)
            {
                if (Thread.CurrentThread == thread)
                {
                    Task task;
                    if (concurrentQ.TryDequeue(out task))
                    {
                        Debug.WriteLine("    Invoking a task");
                        task.RunSynchronously(new SynchronousScheduler());
                    }
                }
                else
                {
                    Debug.Fail("Threaded object running outside its thread");
                }
            }
        }

        public async Task<int> DoThing(int length)
        {
            if (this.IsInWorkerThread())
            {
                Debug.WriteLine("    Running task of length " + length + " on thread " + Thread.CurrentThread.Name);
                Thread.Sleep(length);
                Debug.WriteLine("    Finished task of length " + length);
                return length;
            }
            else
            {
                Debug.WriteLine("Queueing task of length " + length);
                return await Enqueue(()=>DoThing(length).Result);
                //return await Enqueue(async () => await DoThing(length)); //CS0029 cannot implicitly convert type 'void' to 'int'
            }
        }
       
        private Task Enqueue(Action action)
        {
            Task later = new Task(() => action.Invoke());
            concurrentQ.Enqueue(later);
            return later;
        }
        private Task<dynamic> Enqueue(Func<dynamic> action)
        {
            Task<dynamic> later = new Task<dynamic>(() => action.Invoke());
            concurrentQ.Enqueue(later);
            return later;
        }
        private class SynchronousScheduler : TaskScheduler
        {
            protected override IEnumerable<Task> GetScheduledTasks()
            {
                return Enumerable.Empty<Task>();
            }

            protected override void QueueTask(Task task)
            {
                base.TryExecuteTask(task);
            }

            protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued)
            {
                base.TryExecuteTask(task);
                return true;
            }
        }
    }

到目前为止,这令人惊讶。但是,我被告知不要在可以避免使用 Task.Result 时使用它,因为它在某些情况下会死锁,并且在对 lambda 进行排队时,我在从 DoThing 返回时使用它。我可以/应该/如何将Task.Result 替换为await?您可以在下面看到我尝试过的注释,但我对自己正在做的事情的掌握有点太脆弱,无法让它发挥作用。

【问题讨论】:

  • 我怀疑您想在问题标题中将Task.Return 更改为Task.Result
  • 附带说明,RunThread 方法包含一个紧密循环,它劫持了机器的一个核心,并将其从计算设备转换为微型热发生器。你可能想看看BlockingCollection&lt;T&gt; 类来解决这个问题。
  • 说得好,我去看看 Blocking Collection,谢谢

标签: c# multithreading async-await


【解决方案1】:

当你这样做时:

return await Enqueue(async () => await DoThing(length));

它使用EnqueueTask 版本而不是Task&lt;dynamic&gt; 版本。实际上,Enqueue 的重载都不适用于该行。如果注释掉Task Enqueue(Action action),编译器错误变为:

CS4010:无法将异步 lambda 表达式转换为委托类型“Func”。异步 lambda 表达式可能返回 void、Task 或 Task,它们都不能转换为 'Func'。

您需要将Enqueue 中的参数类型(或创建第三个重载,如果需要)更改为Func&lt;Task&lt;dynamic&gt;&gt; 以使其工作。

您对new Task()task.RunSynchronously() 的使用是可疑的,但如果它有效,它就有效。我将不得不让其他人对此发表评论。我对此知之甚少。阅读this question 上的答案可能会帮助您决定是否真的要使用task.RunSynchronously()

【讨论】:

  • 如果我将 Enqueue 的签名更改为 private Task&lt;dynamic&gt; Enqueue(Func&lt;Task&lt;dynamic&gt;&gt; action) 它确实允许我将异步 lambda 传递给它,但是等待“DoThing”会导致 Task 而不是 int 结果,所以我'我不在那里
猜你喜欢
  • 1970-01-01
  • 2013-09-05
  • 1970-01-01
  • 2019-10-06
  • 1970-01-01
  • 2011-03-30
  • 2020-01-23
  • 2017-01-17
  • 1970-01-01
相关资源
最近更新 更多