Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 线程池中有大量线程处于等待状态,导致性能问题_C#_Multithreading_.net 3.5_Threadpool_Scalability - Fatal编程技术网

C# 线程池中有大量线程处于等待状态,导致性能问题

C# 线程池中有大量线程处于等待状态,导致性能问题,c#,multithreading,.net-3.5,threadpool,scalability,C#,Multithreading,.net 3.5,Threadpool,Scalability,我的应用程序通过http连接到大量客户端,从这些客户端下载数据,并在收到这些结果时处理数据。每个请求都在一个单独的线程中发送,这样主线程就不会被占用 我们开始遇到性能问题,这些问题似乎主要与线程池中的大量线程有关,这些线程正在等待从这些请求中获取数据。我知道在.NET4.5中,我们有异步问题,并等待相同类型的问题,但我们仍在使用.NET3.5 您认为在不同的线程中发送这些请求的最佳方式是什么,而不是让该线程保持活动状态,而它所做的一切就是一直等待请求返回吗?您可以在.NET 3.5中使用异步操作

我的应用程序通过http连接到大量客户端,从这些客户端下载数据,并在收到这些结果时处理数据。每个请求都在一个单独的线程中发送,这样主线程就不会被占用

我们开始遇到性能问题,这些问题似乎主要与线程池中的大量线程有关,这些线程正在等待从这些请求中获取数据。我知道在.NET4.5中,我们有异步问题,并等待相同类型的问题,但我们仍在使用.NET3.5


您认为在不同的线程中发送这些请求的最佳方式是什么,而不是让该线程保持活动状态,而它所做的一切就是一直等待请求返回吗?

您可以在.NET 3.5中使用异步操作,但它没有.NET 4.5中方便。大多数IO方法都有一个BeginX/EndX方法对,它是X方法的异步等价物。这就是所谓的

例如,您可以使用Stream.BeginRead和Stream.EndRead代替Stream.Read


实际上,.NET 4.5中的许多异步IO方法只是围绕Begin/End方法的包装。

您可以在.NET 3.5中使用异步操作,但它没有.NET 4.5中方便。大多数IO方法都有一个BeginX/EndX方法对,它是X方法的异步等价物。这就是所谓的

例如,您可以使用Stream.BeginRead和Stream.EndRead代替Stream.Read


实际上,.NET 4.5中的许多异步IO方法只是Begin/End方法的包装。

如果不能使用.NET 4.x和异步/await,您仍然可以使用IEnumerator和yield实现类似的行为。它允许使用带有Begin/End样式回调的伪同步线性代码流,包括像using、try/finally、while/for/foreach等语句

异步枚举器驱动程序有几种实现,例如

我过去用过类似下面的东西:

class AsyncIO
{
    void ReadFileAsync(string fileName)
    {
        AsyncOperationExt.Start(
            start => ReadFileAsyncHelper(fileName, start),
            result => Console.WriteLine("Result: " + result),
            error => Console.WriteLine("Error: " + error));
    }

    static IEnumerator<object> ReadFileAsyncHelper(string fileName, Action nextStep)
    {
        using (var stream = new FileStream(
            fileName, FileMode.Open, FileAccess.Read, FileShare.Read, bufferSize: 1024, useAsync: true))
        {
            IAsyncResult asyncResult = null;
            AsyncCallback asyncCallback = ar => { asyncResult = ar; nextStep(); };
            var buff = new byte[1024];
            while (true)
            {
                stream.BeginRead(buff, 0, buff.Length, asyncCallback, null);
                yield return Type.Missing;
                int readBytes = stream.EndRead(asyncResult);
                if (readBytes == 0)
                    break;
                // process the buff
            }
        }
        yield return true;
    }
}

// ...

// implement AsyncOperationExt.Start
public static class AsyncOperationExt
{
    public static void Start<TResult>(
        Func<Action, IEnumerator<TResult>> start,
        Action<TResult> oncomplete,
        Action<Exception> onerror)
    {
        IEnumerator<TResult> enumerator = null;

        Action nextStep = () =>
        {
            try
            {
                var current = enumerator.Current;
                if (!enumerator.MoveNext())
                    oncomplete(current);
            }
            catch (Exception ex)
            {
                onerror(ex);
            }
            enumerator.Dispose();
        };

        try
        {
            enumerator = start(nextStep);
        }
        catch (Exception ex)
        {
            onerror(ex);
            enumerator.Dispose();
        }
    }
}

如果不能使用.NET4.x和async/await,那么仍然可以使用IEnumerator和yield实现类似的行为。它允许使用带有Begin/End样式回调的伪同步线性代码流,包括像using、try/finally、while/for/foreach等语句

异步枚举器驱动程序有几种实现,例如

我过去用过类似下面的东西:

class AsyncIO
{
    void ReadFileAsync(string fileName)
    {
        AsyncOperationExt.Start(
            start => ReadFileAsyncHelper(fileName, start),
            result => Console.WriteLine("Result: " + result),
            error => Console.WriteLine("Error: " + error));
    }

    static IEnumerator<object> ReadFileAsyncHelper(string fileName, Action nextStep)
    {
        using (var stream = new FileStream(
            fileName, FileMode.Open, FileAccess.Read, FileShare.Read, bufferSize: 1024, useAsync: true))
        {
            IAsyncResult asyncResult = null;
            AsyncCallback asyncCallback = ar => { asyncResult = ar; nextStep(); };
            var buff = new byte[1024];
            while (true)
            {
                stream.BeginRead(buff, 0, buff.Length, asyncCallback, null);
                yield return Type.Missing;
                int readBytes = stream.EndRead(asyncResult);
                if (readBytes == 0)
                    break;
                // process the buff
            }
        }
        yield return true;
    }
}

// ...

// implement AsyncOperationExt.Start
public static class AsyncOperationExt
{
    public static void Start<TResult>(
        Func<Action, IEnumerator<TResult>> start,
        Action<TResult> oncomplete,
        Action<Exception> onerror)
    {
        IEnumerator<TResult> enumerator = null;

        Action nextStep = () =>
        {
            try
            {
                var current = enumerator.Current;
                if (!enumerator.MoveNext())
                    oncomplete(current);
            }
            catch (Exception ex)
            {
                onerror(ex);
            }
            enumerator.Dispose();
        };

        try
        {
            enumerator = start(nextStep);
        }
        catch (Exception ex)
        {
            onerror(ex);
            enumerator.Dispose();
        }
    }
}

@保罗斯诺,是的;BeginRead方法是非阻塞的,当IO操作完成时,您传递给它的回调将在线程池线程上调用,而不会浪费线程等待。正是我想要的:为了补充答案,BeginX/EndX方法使用IO线程,这些线程在内部使用IO完成端口进行非阻塞IO调用。此外,建议不要显式创建线程,而是将任务排队到线程池中,让它为您管理线程。只有当现有线程正在运行或等待时,线程池才会创建线程。使用IOCP,可以最大限度地减少等待时间——因此,如果线程池发送m个请求,其中n个线程m>=n,也就不足为奇了;BeginRead方法是非阻塞的,当IO操作完成时,您传递给它的回调将在线程池线程上调用,而不会浪费线程等待。正是我想要的:为了补充答案,BeginX/EndX方法使用IO线程,这些线程在内部使用IO完成端口进行非阻塞IO调用。此外,建议不要显式创建线程,而是将任务排队到线程池中,让它为您管理线程。只有当现有线程正在运行或等待时,线程池才会创建线程。使用IOCP,您可以最大限度地减少等待时间——因此,如果线程池发送n个线程m>=n的m个请求,也就不足为奇了。