Powershell 和 TaskScheduler 的任务问题

问题描述 投票:0回答:2

我正在编写一个 C# 库 (.NET 4.6.1),它将使用任务来在后台运行多个代码片段。 该库将由从 TaskScheduler 项触发的 Powershell 脚本调用

当我通过启动 Powershell 然后调用库进行测试时,一切正常。 但是,通过 TaskScheduler 它不起作用,我可以使用控制台应用程序复制此行为问题。

主库线程:

public class MainLibrary {
private static HttpClient g_httpclient_Main = new HttpClient();
private static List<Task> g_list_Tasks = new List<Task>();

public void EntryPoint() {
 SetupTasks();

 foreach (Task _t_List in g_list_Tasks)
 {
   _t_List.Start();
 }
 Task.WaitAll(g_list_Tasks.ToArray());
}
}

每个任务都是在 MainLibrary 类的单独函数/方法中的 foreach 循环之前创建的,如下所示:

private void SetupTasks() {
  Task _task_TollGate = new Task(() =>
  {
     QueueEndpointCall();
  });
  g_list_Tasks.Add(_task_TollGate);
}


private async Task QueueEndpointCall()
{
   try {
     HttpResponseMessage _httprm = await g_httpclient_Main.GetAsync("http://www.google.com");
     _string_HTTP = await _httprm.Content.ReadAsStringAsync();
     ....other code
   }
   catch (Exception e) {
     File.WriteLine...
   }
}

当我运行控制台应用程序并设置断点时,当 GetAsync 被命中并运行时,它将跳回到主线程,如果我理解正确的话,这是好的/正确的。然后点击 Task.WaitAll 行,看似后台任务已完成,但我在代码片段“...其他代码”中的占位符未执行。 手动启动 Powershell 并调用库,效果很好。

这里有什么建议吗? 我正在考虑升级到 .NET v8.0,但是目前我没有资源来执行此操作,并且希望在 .NET 4.6.1 中实现此操作

编辑(2025 年 1 月 7 日)- 我迁移到 .NET 8 但没有成功,甚至尝试了在本地声明 HttpClient 的建议,尽管我不认为这是问题,但“...其他代码”仍然是没有被执行。我相信错误正在被吞噬,因为我没有从包装 HttpClient 调用的 try/catch 中看到错误日志文件。

谢谢。

c# task task-parallel-library .net-4.6.1
2个回答
0
投票

我能够让它正常工作:

private readonly static HttpClient g_httpclient_Main = new HttpClient();

public void EntryPoint(string f_string_Metadata)
{
    System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
    List<Task> g_list_Tasks = new List<Task>();
    SetupTasks(g_list_Tasks);

    foreach (Task _t_List in g_list_Tasks)
    {
        _t_List.Start();
    }
    Task.WaitAll(g_list_Tasks.ToArray());
}

private void SetupTasks(List<Task> f_List)
{
    Task _task_TollGate = new Task(() =>
    {
        QueueEndpointCall();
    });
    f_List.Add(_task_TollGate);
}

private void QueueEndpointCall()
{
    Task<string> _t = g_httpclient_Main.GetStringAsync("http://www.google.com");
    Task.WaitAll(_t);
    Console.WriteLine(_t.Result);
}

GetStringAsync 也与我的原始代码片段中的 GetAsync 调用类似,当从主线程调用 Task.WaitAll 时似乎没有等待。 因此,我从 GetStringAsync 调用中获取了 Task 对象,并对其执行了 Task.WaitAll。一旦我这样做了,代码流就会在完成 GetStringAsync 操作后到达 Console.WriteLine。


-1
投票

删除静态变量

g_httpclient_Main
并在方法
QueueEndpointCall
中本地声明它。
HttpClient
不是线程安全的。 每个任务都需要一个新实例,因为它们不是按顺序运行的。

© www.soinside.com 2019 - 2024. All rights reserved.