c# - 代码有效,但似乎同步运行而不是异步运行

标签 c# multithreading asynchronous

static void Main(string[] args)
{
    // do async method for each stock in the list
    Task<IEnumerable<string>> symbols = Helper.getStockSymbols("amex", 0);
    List<Task> tasks = new List<Task>();

    try
    {
        for (int i = 0; i < symbols.Result.Count(); i++)
        {
            if (i < symbols.Result.Count())
            {
                string symbol = symbols.Result.ElementAtOrDefault(i);
                Task t = Task.Run(() => getCalculationsDataAsync(symbol, "amex"));
                tasks.Add(t);
                Task e = t.ContinueWith((d) => getThreadStatus(tasks));
            }
        }

        // don't exit until they choose to
        while (args.FirstOrDefault() != "exit")
        {
            // do nothing

        }
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message);
    }
}

public static void getThreadStatus(List<Task> taskList)
{
    int count = 0;

    foreach (Task t in taskList)
    {
        if (t.Status == TaskStatus.Running)
        {
            count += 1;
        }
    }

    Console.WriteLine(count + " threads are running.");
}

public static async Task getCalculationsDataAsync(string symbol, string market)
{
    // do calculation here
}

我在我的代码中尝试做的是为我列表中的每只股票运行一个新任务,并同时运行它们。我有一个 4 核处理器,我相信这意味着我一次只能运行 4 个任务。我尝试通过插入您在我的代码中看到的 continuewith 方法来测试正在运行的任务数,该方法会告诉我有多少任务正在运行。当我运行这段代码时,它告诉我有 0 个任务正在运行,所以我的问题是:

  1. 如何通过同时运行这些任务来完成我的目标?
  2. 为什么它告诉我 0 个任务正在运行?我只能假设这是因为当前任务已完成,如果任务一个接一个地运行,它还没有开始新的任务。

最佳答案

我不确定您为什么没有看到任何任务在运行。你确定你的Task.Run()被击中?也就是说是i < symbols.Result.Count()使满意?

不管以上情况如何,让我们尝试实现您想要的。首先,不,说因为你的机器有四个物理核心/“线程”,所以你最多可以使用四个 Thread 是不正确的。秒。这些不是一回事。关于这个主题的谷歌会为你带来大量关于这方面的信息。

基本上,按照您的方式启动线程将在线程池上启动后台线程,并且该线程池可以容纳/管理大量线程,请参阅Threading in C# by J. Albahari了解更多信息。每当您启动一个线程时,都会花费几百微秒来组织诸如新的私有(private)局部变量堆栈之类的东西。每个线程还消耗(默认情况下)大约 1 MB 的内存。线程池通过共享和回收线程来减少这些开销,允许在非常精细的级别应用多线程,而不会降低性能。这在利用多核处理器以“分而治之”的方式并行执行计算密集型代码时非常有用。

线程池还会限制同时运行的工作线程总数。过多的事件线程会以管理负担扼杀操作系统,并导致 CPU 缓存失效。一旦达到限制,作业就会排队并仅在另一个完成时才开始。

好的,现在开始你的代码。假设我们有一个股票类型列表

List<string> types = new List<string>() { "AMEX", "AMEC", "BP" };

要分派(dispatch)多个线程为其中的每一个做(不使用 async/await ),你可以做类似的事情

foreach (string t in types)
{
    Task.Factory.StartNew(() => DoSomeCalculationForType(t));
}

这将触发三个后台线程池线程并且是非阻塞的,所以这段代码几乎会立即返回给调用者。

如果您想设置后处理,您可以通过延续和延续链接来实现。我在上面提供的 Albahari 链接中描述了所有这些内容。

希望对您有所帮助。

--

编辑。处理评论:

Beginning with the .NET Framework version 4, the default size of the thread pool for a process depends on several factors, such as the size of the virtual address space. A process can call the GetMaxThreads method to determine the number of threads.

但是,还有其他因素在起作用:线程池不会在所有情况下都立即创建新线程。为了应对突发的小任务,它限制了创建新线程的速度。 IIRC,如果有未完成的任务,它将每 0.5 秒创建一个线程,直到最大线程数。虽然我不能立即看到记录的数字,所以它很可能会改变。我强烈怀疑这就是你所看到的。尝试对大量项目进行排队,然后随时间监控线程数。

基本上让线程池调度它想要的东西,它的优化器会根据您的情况做最好的工作。

关于c# - 代码有效,但似乎同步运行而不是异步运行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23507347/

相关文章:

c# - 授予非管理员用户访问权限以启动/停止服务 Windows 7

cocoa - 在 cocoa os x 上创建自定义事件/信号

python - 使用 python 和 tkinter 实时绘制串行数据

ruby - ruby 中的 fork 和线程

asynchronous - 现实世界中跨平台的分散式异步对等通信

c# - 使用 xamarin.forms 的 iOS 应用程序链接

c# - EF 4.1 - 无法将一个实体与另一个现有实体相关联(可空 FK)

c# - 在 try 语句内调用 Monitor.Enter 与在 try 语句外调用它

javascript - 如何等到 localStorage.setItem 在 Angular 4 中完成

c# - 在 C#/Winforms 中使 Web 服务方法异步