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

时间:2014-05-03 23:38:55

标签: c# multithreading .net-3.5 threadpool scalability

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

我们已经开始遇到性能问题,看起来这些问题主要与ThreadPool中仅等待从这些请求中获取数据的大量线程有关。我知道在.NET 4.5中我们有asyncawait用于同一类型的问题,但我们仍在使用.NET 3.5。

对于在不同线程中发送这些请求的最佳方式有什么想法,但不是为了让该线程保持活动状态,而是在等待请求返回?

2 个答案:

答案 0 :(得分:3)

您可以在.NET 3.5中使用异步操作,它不像.NET 4.5那样方便。大多数IO方法都有BeginX / EndX方法对,它是X方法的异步等效项。这称为Asynchronous Programming Model (APM)

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

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

答案 1 :(得分:1)

如果您无法使用.NET 4.x和async/await,您仍然可以使用IEnumeratoryield实现某种类似的行为。它允许使用带有Begin/End样式回调的伪同步线性代码流,包括usingtry/finallywhile/for/foreach等语句。尽管你cannot use try/catch

异步枚举器驱动程序有一些实现,例如Jeffrey Richter's AsyncEnumerator

我过去使用过类似的东西:

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();
        }
    }
}