为什么这些任务在同一线程中启动?

游击队

我试图更好地理解线程,但遇到了让我感到困惑的事情。据我所知Task.Run()在另一个线程中启动任务。

我在下面构建了一些代码来对其进行测试,以查看其行为,但是我的理解存在漏洞。

我以为我可以像这样循环执行任务:

    public void DoTheThings(List<string> inputList)
    {
        List<Task> taskList = new List<Task>();

        foreach (var input in inputList)
        {
            taskList.Add(Task.Run(() => this.GetTheStuff(input)));
        }
        Task.WaitAll(taskList.ToArray());
        Console.WriteLine("Queue completed");
    }

如果调用的任务(GetTheStuff())延迟,则它将锁定该线程,因此下一个启动的任务将位于新线程中:

    public async Task GetTheStuff(string input)
    {
        Console.WriteLine("Thread " + Thread.CurrentThread.ManagedThreadId + "starting");
        int delay = GetRandomNumber(1000, 5000); // simulate time of a http request or something similar
        var notInUse = input; // in real app this would be some useful assignment
        await Task.Delay(delay);

        Console.WriteLine("Thread " + Thread.CurrentThread.ManagedThreadId + "ending");
    }

但这不会发生。相同的线程用于启动多个任务。大概是通过查看函数开头和结尾处的“ ManagedThreadID”来实现的。

在我的错误假设中,我认为Main()函数将是一个线程。它将为DoTheThings()启动一个新线程,然后此函数将为并发GetTheStuff()处理启动多个线程。

实际发生了什么?

完整的代码:

class Program
{

    private static void Main(string[] args)
    {
        // build list of 100 random strings to represent input
        List<string> thingsToProcess = new List<string>();
        for (int i = 0; i < 100; i++)
        {
            thingsToProcess.Add(Path.GetRandomFileName());
        }
        Console.WriteLine("Starting queue");
        var m = new MethodStuff();
        var mainTask = Task.Run(() => m.DoTheThings(thingsToProcess));

        Task.WaitAll(mainTask);
        Console.WriteLine("All done");
        Console.ReadLine();

    }

}
class MethodStuff
{
    private static readonly Random getrandom = new Random();
    private static readonly object syncLock = new object();
    public static int GetRandomNumber(int min, int max)
    {
        lock (syncLock)
        { // synchronize
            return getrandom.Next(min, max);
        }
    }
    // loop over all input and start each input in its own thread
    public void DoTheThings(List<string> inputList)
    {
        List<Task> taskList = new List<Task>();

        foreach (var input in inputList)
        {
            taskList.Add(Task.Run(() => this.GetTheStuff(input)));
        }
        Task.WaitAll(taskList.ToArray());
        Console.WriteLine("Queue completed");
    }

    public async Task GetTheStuff(string input)
    {
        Console.WriteLine("Thread " + Thread.CurrentThread.ManagedThreadId + "starting");
        int delay = GetRandomNumber(1000, 5000); // simulate time of a http request or something similar
        var notInUse = input; // in real app this would be some useful assignment
        await Task.Delay(delay);

        Console.WriteLine("Thread " + Thread.CurrentThread.ManagedThreadId + "ending");
    }
}
消费者

您真的应该问一个有关您实际上要解决的问题的问题:)

据我所知,您可能正在发出同步HTTP请求,并尝试通过将其触发来并行化它们Task.Run这会将它们排队到Threadpool,该线程池最初可能只包含与计算机上的vcore一样多的线程。假设您的HTTP请求是同步发出的,这将占用运行请求的池线程,直到请求完成。当达到与池中线程数相同的任务数时,队列将暂停,直到ThreadPool池任务完成或ThreadPool决定启动另一个线程。ThreadPool不会在任何紧急情况下启动线程,因此这会给方程式带来各种延迟。

获得高吞吐量的一个很好的经验法则是永远不要将阻塞的工作负载放到ThreadPool中。同步HTTP是一个阻塞的工作负载。

您应该切换异步Web请求,最好使用基于任务的异步和async / await关键字。如果做得正确,您将能够在不消耗ThreadPool的情况下触发数千个请求(尽管您的网络设备可能开始发牢骚……SOHO路由器对于这种情况非常不利)。

可能阻止高吞吐量的其他问题:

如果您从许多不同的主机发出请求,则可能选择使用第三方dns库,因为Web请求中的.Net DNS查找阶段始终同步运行。这太烂了。现在,您可以在HttpWebRequest中使用从库返回的IP地址,并将Host属性手动设置为您要访问的主机的名称。我发现这可以大大改善HTTP请求的性能。

如果要向同一主机发出大量请求,则可能需要进行调整,ServicePointManager.DefaultConnectionLimit以便可以一次向一个主机发出两个(或6个以上,具体取决于上下文)请求。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

为什么这些任务在同一线程中启动?

来自分类Dev

为什么必须使用同一线程?

来自分类Dev

如果它在android的同一线程中运行,为什么要使用Service

来自分类Dev

为什么我得到这个结果(在退出之前,同一线程进入两次)?

来自分类Dev

为什么 View.getHeight() 在同一线程上完成测量传递时返回 0?

来自分类Dev

多次启动/调用同一线程Java Android

来自分类Dev

多次启动/调用同一线程Java Android

来自分类Dev

在同一线程内的线程中调用实例

来自分类Dev

在同一线程NUnit中运行所有测试

来自分类Dev

从同一线程内部中止线程

来自分类Dev

在同一线程上运行块

来自分类Dev

WebBrowser在同一线程上运行

来自分类Dev

Streamlit-在线程中创建的SQLite对象只能在同一线程中使用

来自分类Dev

jmeter 同一线程中不同http请求的不同线程数

来自分类Dev

如何在需要时暂停正在运行的线程并重新启动同一线程?

来自分类Dev

为什么任务在主线程中运行?

来自分类Dev

在SpriteKit中,touchesBegan是否与SKScene更新方法在同一线程中运行?

来自分类Dev

为什么现代OS(Linux,Windows,Solaris)实现一对一线程模型?

来自分类Dev

为什么现代OS(Linux,Windows,Solaris)实现一对一线程模型?

来自分类Dev

在执行CUDA设备代码的同时在同一线程中运行主机代码

来自分类Dev

NSNotificationQueue,发送方和处理程序是否必须在同一线程中?

来自分类Dev

使用ThreadPoolExecutor在同一线程中的Runnable实例之间共享数据

来自分类Dev

P / Invoke调用的方法是否在同一线程中运行?

来自分类Dev

JMeter变量值在同一线程组和简单控制器中丢失

来自分类Dev

使用ThreadPoolExecutor在同一线程中的Runnable实例之间共享数据

来自分类Dev

异步不会在单元测试中的同一线程上继续

来自分类Dev

PyQt QThread:如何在同一线程中的工作对象上运行函数?

来自分类Dev

为什么这些类仅在同一文件中才编译?

来自分类Dev

为什么这些类仅在同一文件中才编译?

Related 相关文章

  1. 1

    为什么这些任务在同一线程中启动?

  2. 2

    为什么必须使用同一线程?

  3. 3

    如果它在android的同一线程中运行,为什么要使用Service

  4. 4

    为什么我得到这个结果(在退出之前,同一线程进入两次)?

  5. 5

    为什么 View.getHeight() 在同一线程上完成测量传递时返回 0?

  6. 6

    多次启动/调用同一线程Java Android

  7. 7

    多次启动/调用同一线程Java Android

  8. 8

    在同一线程内的线程中调用实例

  9. 9

    在同一线程NUnit中运行所有测试

  10. 10

    从同一线程内部中止线程

  11. 11

    在同一线程上运行块

  12. 12

    WebBrowser在同一线程上运行

  13. 13

    Streamlit-在线程中创建的SQLite对象只能在同一线程中使用

  14. 14

    jmeter 同一线程中不同http请求的不同线程数

  15. 15

    如何在需要时暂停正在运行的线程并重新启动同一线程?

  16. 16

    为什么任务在主线程中运行?

  17. 17

    在SpriteKit中,touchesBegan是否与SKScene更新方法在同一线程中运行?

  18. 18

    为什么现代OS(Linux,Windows,Solaris)实现一对一线程模型?

  19. 19

    为什么现代OS(Linux,Windows,Solaris)实现一对一线程模型?

  20. 20

    在执行CUDA设备代码的同时在同一线程中运行主机代码

  21. 21

    NSNotificationQueue,发送方和处理程序是否必须在同一线程中?

  22. 22

    使用ThreadPoolExecutor在同一线程中的Runnable实例之间共享数据

  23. 23

    P / Invoke调用的方法是否在同一线程中运行?

  24. 24

    JMeter变量值在同一线程组和简单控制器中丢失

  25. 25

    使用ThreadPoolExecutor在同一线程中的Runnable实例之间共享数据

  26. 26

    异步不会在单元测试中的同一线程上继续

  27. 27

    PyQt QThread:如何在同一线程中的工作对象上运行函数?

  28. 28

    为什么这些类仅在同一文件中才编译?

  29. 29

    为什么这些类仅在同一文件中才编译?

热门标签

归档