【发布时间】: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<T>类来解决这个问题。 -
说得好,我去看看 Blocking Collection,谢谢
标签: c# multithreading async-await