Whenany() 在任务列表中退出程序
Whenany() on task list is exiting the program
我有一个控制台应用程序,我在其中使用 TPL,当我在任务中点击 whenany 时它会退出。我是线程的新手,有人可以指导我正确的方向吗(我单独执行了 RunJob,它没有例外..所以我不确定如何从这里进行调试。
代码如下:
// Program.cs
static void Main(string[] args)
{
TaskHelper helper = new TaskHelper();
helper.StartProcessing();
}
// TaskHelper Class
public async void StartProcessing()
{
var tasks = new List<Task<bool>>();
int taskNum = _queueList.Count < maxThreads ? _queueList.Count : maxThreads;
for (int i = 0; i < taskNum; i++)
{
UCMDo doObj;
if (_taskQueue.TryDequeue(out doObj))
{
tasks.Add(RunOps(doObj));
}
}
while (tasks.Count > 0)
{
try
{
// Program exits here when its hitting WhenAny line
var t = await Task.WhenAny(tasks);
tasks.Remove(t);
await t;
}
catch (OperationCanceledException)
{
}
catch (Exception exc) { }
finally
{
// add to tasks, and RunOps
}
}
}
async Task<bool> RunOps(UCMDo doJ)
{
var result = await Task.Run(() => UCMFactory.RunJob(_job, doJ));
return result;
}
发生的事情是你调用 StartProcessing
而不等待它(你不能,因为它是 async void
)所以程序到达 Main
的末尾并在操作时结束在 StartProcessing
中仍然是 运行.
StartProcessing
应该 return 一项任务,您应该等待该任务完成。这通常是通过等待任务(即 await helper.StartProcessing()
)来完成的,但由于您不能在 Main
中使用 await
,因此您应该同步执行此操作(尽管这是唯一可以接受的地方):
static void Main(string[] args)
{
TaskHelper helper = new TaskHelper();
helper.StartProcessingAsync().Wait();
}
正如 Servy 正确指出的那样,一个更健壮和生产就绪的解决方案是使用某种消息循环。一个例子是 Stephen Cleary's AsyncContext
:
static void Main(string[] args)
{
TaskHelper helper = new TaskHelper();
AsyncContext.Run(() => helper.StartProcessingAsync());
}
备注:
async void
绝不能在 UI 事件处理程序之外使用
async
方法一般应命名为XAsync
(即StartProcessingAsync
)
我有一个控制台应用程序,我在其中使用 TPL,当我在任务中点击 whenany 时它会退出。我是线程的新手,有人可以指导我正确的方向吗(我单独执行了 RunJob,它没有例外..所以我不确定如何从这里进行调试。
代码如下:
// Program.cs
static void Main(string[] args)
{
TaskHelper helper = new TaskHelper();
helper.StartProcessing();
}
// TaskHelper Class
public async void StartProcessing()
{
var tasks = new List<Task<bool>>();
int taskNum = _queueList.Count < maxThreads ? _queueList.Count : maxThreads;
for (int i = 0; i < taskNum; i++)
{
UCMDo doObj;
if (_taskQueue.TryDequeue(out doObj))
{
tasks.Add(RunOps(doObj));
}
}
while (tasks.Count > 0)
{
try
{
// Program exits here when its hitting WhenAny line
var t = await Task.WhenAny(tasks);
tasks.Remove(t);
await t;
}
catch (OperationCanceledException)
{
}
catch (Exception exc) { }
finally
{
// add to tasks, and RunOps
}
}
}
async Task<bool> RunOps(UCMDo doJ)
{
var result = await Task.Run(() => UCMFactory.RunJob(_job, doJ));
return result;
}
发生的事情是你调用 StartProcessing
而不等待它(你不能,因为它是 async void
)所以程序到达 Main
的末尾并在操作时结束在 StartProcessing
中仍然是 运行.
StartProcessing
应该 return 一项任务,您应该等待该任务完成。这通常是通过等待任务(即 await helper.StartProcessing()
)来完成的,但由于您不能在 Main
中使用 await
,因此您应该同步执行此操作(尽管这是唯一可以接受的地方):
static void Main(string[] args)
{
TaskHelper helper = new TaskHelper();
helper.StartProcessingAsync().Wait();
}
正如 Servy 正确指出的那样,一个更健壮和生产就绪的解决方案是使用某种消息循环。一个例子是 Stephen Cleary's AsyncContext
:
static void Main(string[] args)
{
TaskHelper helper = new TaskHelper();
AsyncContext.Run(() => helper.StartProcessingAsync());
}
备注:
async void
绝不能在 UI 事件处理程序之外使用async
方法一般应命名为XAsync
(即StartProcessingAsync
)