0

我需要测试我们的应用程序中是否有任何内存泄漏,并监视内存使用量在处理请求时是否增加太多。 我正在尝试开发一些代码,以便对我们的api/webservice方法进行多个同时调用。此api方法不是异步的,需要一些时间才能完成操作。c#如何加载测试Web服务

我已经做了大量关于任务,线程和并行的研究,但到目前为止我还没有运气。问题是,即使在尝试了所有下面的解决方案之后,结果总是相同的,但它似乎只处理当时的两个请求。

尝试:

- >内创建一个简单的任务和循环使用和不使用TaskCreationOptions.LongRunning

设置它们

启动它们 - >内创建一个简单的线程循环,有和没有他们开始高优先级

- >创建的for循环的一个简单的动作列表,并使用启动它们

Parallel.Foreach(list, options, item => item.Invoke) 

- >直接一个的Parallel.For循环(下面)

内部运行 - >运行有和没有选项和TPL的TaskScheduler方法

- >有用于MaxParallelism和最大线程

不同的值试图

- >也检查了this post,但它也没有帮助。 (我可能会错过什么?)

- >检查一些其他帖子在这里在Stackoverflow,但与F#解决方案,我不知道如何正确地将它们转换为C#。 (我从来没有使用F#...)

(从msdn拍摄任务调度器类)

这里的基本结构,我有:

public class Test 
{ 
    Data _data; 
    String _url; 

    public Test(Data data, string url) 
    { 
     _data = data; 
     _url = url; 
    } 

    public ReturnData Execute() 
    { 
     ReturnData returnData; 

     using(var ws = new WebService()) 
     { 
       ws.Url = _url; 
       ws.Timeout = 600000; 

       var wsReturn = ws.LongRunningMethod(data); 

       // Basically convert wsReturn to my method return, with some logic if/else etc 
     } 
     return returnData; 
    } 
} 

sealed class ThreadTaskScheduler : TaskScheduler, IDisposable 
    { 
     // The runtime decides how many tasks to create for the given set of iterations, loop options, and scheduler's max concurrency level. 
     // Tasks will be queued in this collection 
     private BlockingCollection<Task> _tasks = new BlockingCollection<Task>(); 

     // Maintain an array of threads. (Feel free to bump up _n.) 
     private readonly int _n = 100; 
     private Thread[] _threads; 

     public TwoThreadTaskScheduler() 
     { 
      _threads = new Thread[_n]; 

      // Create unstarted threads based on the same inline delegate 
      for (int i = 0; i < _n; i++) 
      { 
       _threads[i] = new Thread(() => 
       { 
        // The following loop blocks until items become available in the blocking collection. 
        // Then one thread is unblocked to consume that item. 
        foreach (var task in _tasks.GetConsumingEnumerable()) 
        { 
         TryExecuteTask(task); 
        } 
       }); 

       // Start each thread 
       _threads[i].IsBackground = true; 
       _threads[i].Start(); 
      } 
     } 

     // This method is invoked by the runtime to schedule a task 
     protected override void QueueTask(Task task) 
     { 
      _tasks.Add(task); 
     } 

     // The runtime will probe if a task can be executed in the current thread. 
     // By returning false, we direct all tasks to be queued up. 
     protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued) 
     { 
      return false; 
     } 

     public override int MaximumConcurrencyLevel { get { return _n; } } 

     protected override IEnumerable<Task> GetScheduledTasks() 
     { 
      return _tasks.ToArray(); 
     } 

     // Dispose is not thread-safe with other members. 
     // It may only be used when no more tasks will be queued 
     // to the scheduler. This implementation will block 
     // until all previously queued tasks have completed. 
     public void Dispose() 
     { 
      if (_threads != null) 
      { 
       _tasks.CompleteAdding(); 

       for (int i = 0; i < _n; i++) 
       { 
        _threads[i].Join(); 
        _threads[i] = null; 
       } 
       _threads = null; 
       _tasks.Dispose(); 
       _tasks = null; 
      } 
     } 
    } 

而且测试代码本身:

private void button2_Click(object sender, EventArgs e) 
    { 
     var maximum = 100; 
     var options = new ParallelOptions 
     { 
      MaxDegreeOfParallelism = 100, 
      TaskScheduler = new ThreadTaskScheduler() 
     }; 

     // To prevent UI blocking 
     Task.Factory.StartNew(() => 
     { 
      Parallel.For(0, maximum, options, i => 
      { 
       var data = new Data(); 
       // Fill data 
       var test = new Test(data, _url); //_url is pre-defined 
       var ret = test.Execute(); 

       // Check return and display on screen 
       var now = DateTime.Now.ToString("HH:mm:ss"); 
       var newText = $"{Environment.NewLine}[{now}] - {ret.ReturnId}) {ret.ReturnDescription}"; 

       AppendTextBox(newText, ref resultTextBox); 
      } 
    } 

    public void AppendTextBox(string value, ref TextBox textBox) 
    { 
     if (InvokeRequired) 
     { 
      this.Invoke(new ActionRef<string, TextBox>(AppendTextBox), value, textBox); 
      return; 
     } 
     textBox.Text += value; 
    } 

而我得到的结果基本上是这样的:

[10:08:56] - (0) OK 
[10:08:56] - (0) OK 
[10:09:23] - (0) OK 
[10:09:23] - (0) OK 
[10:09:49] - (0) OK 
[10:09:50] - (0) OK 
[10:10:15] - (0) OK 
[10:10:16] - (0) OK 
etc 

据我所知,服务器端没有限制。我对并行/多任务处理领域相对陌生。有没有其他方法可以做到这一点?我错过了什么吗?我简化了所有代码的清晰性,我相信所提供的代码足以描述上述场景。我也没有发布应用程序代码,但它是一个简单的WinForms屏幕,只是为了调用和显示结果。如果任何代码有某种相关性,请告诉我,我可以编辑并发布。)

在此先感谢!

EDIT1:我检查了服务器日志,它收到的请求两个两个,所以这确实是有关发送它们,没有收到。 它可能是一个与框架如何管理请求/连接有关的网络问题/限制吗?或者与网络有什么关系(与.net无关)?

编辑2:忘了提及,它是一个SOAP web服务。

EDIT3:我发送的一个属性(内部数据)需要为每个请求更改。编辑4:我注意到每对请求之间总是有25秒的时间间隔,如果相关的话。

+0

您是否尝试过使用[Web Test](https://msdn.microsoft.com/en-us/library/ms182536(v = vs.90).aspx)?您可以记录特定的请求,然后将其作为[VS Load Test]的一部分运行(https://www.visualstudio.com/en-us/docs/test/performance-testing/getting-started/getting-started-与性能测试)。 – G0dsquad

+0

谢谢,我没有试过,会看看它。但我只需要测试webmethod,没有UI。使用Web测试可以实现吗?是否可以同时运行很多次?因为我需要同时访问服务器的请求,或者最接近服务器的请求。 –

+0

当然,如果WebMethod具有HTTP端点,则可以使用Web测试记录请求(例如数据POST)。然后,您可以配置负载测试,以10分钟的时间用真实的思考时间说50个并行用户。 – G0dsquad

回答

2

我建议不要另起炉灶,只需使用现有的解决方案之一:

  1. 最明显的选择:如果您的Visual Studio许可允许,您可以使用MS负载测试框架,最有可能你赢了”吨甚至需要编写一行代码:How to: Create a Web Service Test
  2. SoapUI是一个自由和开源Web服务测试工具,它有一些有限的load testing capabilities
  3. 如果由于某种原因了SoapUI不适合(即你需要运行负荷测试在几个主机或哟集群模式您需要更多增强的报告),您可以使用Apache JMeter - 免费和开源的多协议负载测试工具,它也支持web services load testing
+0

感谢您的回复!我编辑了这个问题,还有一件事:对于每个请求,我需要更改我发送的对象的属性之一。我可以用这些工具来实现吗? (我仍在阅读文档) –

+0

所有3个选项都可以使用,Visual Studio拥有.NET框架的所有功能,对于SoapUI和JMeter,您可以使用[Groovy语言](https://www.blazemeter。 com/blog/groovy-new-black)作为脚本解决方案,同样在JMeter中,您可以使用GUI配置所有内容(随机化数据或从CSV文件,数据库中获取数据)。 –

+0

我设法通过在服务器上运行它,使用更强大的CPU。它看起来像我的电脑无法启动尽可能多的线程,然后按照我的要求运行。但是这些都是一些很好的解决方案,我会在下次考虑这一点。谢谢! –

1

一个很好的解决方案来创建负载测试没有写一个自己的项目是使用这项服务https://loader.io/targets

它是免费的小测试,你可以POST参数,头,...你有一个很好的报告。

+0

感谢您的回应,但我们需要进行一些相对较大的测试,我们的测试环境不对互联网开放。我一直在寻找更灵活/可控的东西,这就是为什么我们要制作自己的测试项目。 –