C#线程使用Ram

时间:2016-08-19 18:46:55

标签: c# multithreading

我正在创建一个网页flooder来测试我服务器上的某些安全性。 我有这段代码:

static void Main(string[] args)
{
    string url;
    int times;
    Console.WriteLine("Inserisci l'indirizzo(pagina specifica) da floodare");
    url = Console.ReadLine();
    Console.WriteLine("Quante volte?");
    times = Int32.Parse(Console.ReadLine());
    System.Net.ServicePointManager.DefaultConnectionLimit = 350;
    var block = new System.Threading.Tasks.Dataflow.ActionBlock<int>(async i =>
    {
        try
        {
            await Work(i, url);
        }
        catch (Exception e)
        {

        }
    }, new System.Threading.Tasks.Dataflow.ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = 350 });

    for(int i = 0; i < times; i++)
    {
        block.Post(i);
    }
    block.Complete();

    Task.WaitAll(block.Completion);
}
private static async Task<bool> Work(int i, string url)
{
    if (i % 1000 == 0)
        Console.WriteLine(i);

    new WebClient().UploadValuesTaskAsync(url, new System.Collections.Specialized.NameValueCollection());

    //await Task.Delay(1);
    return true;
}
}

它的工作做得很好,但它有一个问题。如果我设置的请求数量非常高(如200万或更多),它会使用很多内存。在130万请求它使用3.3gb的RAM。我试图处理所有东西,以任何方式释放ram但似乎block变量存储每个线程直到它完成。我该如何解决这个问题?

2 个答案:

答案 0 :(得分:2)

Work中,您不必等待IO完成。这使Work非常快速地完成。这有效地禁用了您想要的速率限制(MaxDegreeOfParallelism = 350)。

工作开始的速度比完成时快得多。这就是工作项积累和消耗内存的原因。

等待IO完成。

答案 1 :(得分:1)

我发现了什么。您正在使用WebClient,但不要将其丢弃。 WebClient leaks

工作方法应该是这样的:

private static async Task<bool> Work(int i, string url)
{
    if (i % 1000 == 0)
        Console.WriteLine(i);

    // Must dispose to avoid leaks
    using (var wc = new WebClient())
    {
        await wc.UploadValuesTaskAsync(url, new System.Collections.Specialized.NameValueCollection());
    }
    //await Task.Delay(1);
    return true;
}

<强>更新 我使用HttpWebRequest和异步方法BeginGetResponse来解决您的问题。完整代码为https://dotnetfiddle.net/ZecQku

namespace HttpWebRequest_HighIntesive
{
    using System;
    using System.Diagnostics;
    using System.Net;
    using System.Threading;

    class ThreadParam
    {
        public int RequestsCount { get; private set; }
        public CountdownEvent CountdownEvent { get; private set; }
        public ThreadParam(int requestsCount, CountdownEvent countdownEvent)
        {
            RequestsCount = requestsCount;
            CountdownEvent = countdownEvent;
        }
    }
    class FinistRequestParam
    {
        public CountdownEvent CountdownEvent { get; private set; }
        public HttpWebRequest HttpWebRequest { get; private set; }
        public FinistRequestParam(CountdownEvent countdownEvent, HttpWebRequest httpWebRequest)
        {
            CountdownEvent = countdownEvent;
            HttpWebRequest = httpWebRequest;
        }
    }
    public class Program
    {
        static Uri _uri;
        static volatile int _numberOfFinishedRequests;
        static double _prevMemoryMb = 0;

        public static int Main(string[] args)
        {
            int numOfRequests;
            Console.Write("Enter URL(full format, for example, http://google.ru): ");
            var url = Console.ReadLine();
            if (!Uri.TryCreate(url, UriKind.RelativeOrAbsolute, out _uri)){
                Console.WriteLine("Invalid URL. Exiting"); return -1;
            }
            Console.Write("Enter number of requests: ");
            numOfRequests = Int32.Parse(Console.ReadLine());

            Console.WriteLine("");
            DoParallelRequests(numOfRequests);

            Console.WriteLine("Finished. Press 'Enter' to quit");
            Console.ReadLine();
            return 0;
        }
        private static void DoParallelRequests(int numOfRequests)
        {
            // Play with DefaultConnectionLimit
            // Increasing this value will increase speed, but also increase memory consumption
            System.Net.ServicePointManager.DefaultConnectionLimit = 350;
            Console.WriteLine("DefaultConnectionLimit: {0}", System.Net.ServicePointManager.DefaultConnectionLimit);
            int threadCnt = Environment.ProcessorCount;
            Console.WriteLine("Num of threads which creates HttpWebRequest: {0}", threadCnt);
            // Initialize CountDownEvent with numOfRequests
            CountdownEvent countDownOnTimes = new CountdownEvent(numOfRequests);
            // Create timer for statistics
            using (var timer = new Timer(TimerStatisticHanlder, Stopwatch.StartNew(), TimeSpan.FromSeconds(2), TimeSpan.FromSeconds(5)))
            {
                // Create thread array
                Thread[] threads = new Thread[threadCnt];
                // Initialize each thread and start it
                for (int i = 0; i < threads.Length; i++)
                {
                    threads[i] = new Thread(ThreadMethod);
                    // HACK Hope numOfRequests % threadCnt == 0 (evenly divisible)
                    // Start thread
                    threads[i].Start(new ThreadParam(numOfRequests / threadCnt, countDownOnTimes));
                }
                // Will wait untill all request processed
                countDownOnTimes.Wait();
            }
        }
        static void TimerStatisticHanlder(object obj)
        {
            Stopwatch sw = obj as Stopwatch;
            // Calculate average speed
            var aveageSpeed = Math.Round(_numberOfFinishedRequests / sw.Elapsed.TotalSeconds, 2);
            // Get total memory
            var totalMemoryMb = Math.Round((double)GC.GetTotalMemory(false) / 1024 / 1024);
            // Calculate memory delta
            var memoryDeltaMb = totalMemoryMb - _prevMemoryMb;
            // Print out statistics
            Console.WriteLine("{0} Processed requests: {1}, Average speed: {2} requests per/s, Used memory: {3} Mbytes, Memory delta: {4}", DateTime.Now.ToString("HH:mm:ss"), _numberOfFinishedRequests, aveageSpeed, totalMemoryMb, memoryDeltaMb);
            // Store total memory for delta calculation
            _prevMemoryMb = totalMemoryMb;
        }
        private static void ThreadMethod(object state)
        {
            var threadParam = state as ThreadParam;
            for (int i = 0; i <= threadParam.RequestsCount; i++)
            {
                // Create HttpWebRequest
                HttpWebRequest request = (HttpWebRequest)WebRequest.Create(_uri);
                // Start it asynchronous
                request.BeginGetResponse(new AsyncCallback(FinishRequest), new FinistRequestParam(threadParam.CountdownEvent, request));
            }
        }
        private static void FinishRequest(IAsyncResult result)
        {
            var reqParam = result.AsyncState as FinistRequestParam;
            var request = reqParam.HttpWebRequest;
            try
            {
                // Just end response
                HttpWebResponse response = request.EndGetResponse(result) as HttpWebResponse;
                // Release all resources
                response.GetResponseStream().Dispose();
                response.Close();
                (request as IDisposable).Dispose();
            }
            catch { } // Don't care about exceptions

            // Mark yet another request finished
            reqParam.CountdownEvent.Signal();
            // Increment total number of finished requests
            Interlocked.Increment(ref _numberOfFinishedRequests);
        }
    }
}

测试应用程序屏幕: Scree of test app