c#如何加载测试Web服务

c#如何加载测试Web服务,c#,web-services,parallel-processing,task-parallel-library,load-testing,C#,Web Services,Parallel Processing,Task Parallel Library,Load Testing,我需要测试我们的应用程序中是否存在内存泄漏,并在处理请求时监视内存使用是否增加过多。 我正试图开发一些代码来同时调用我们的api/webservice方法。此api方法不是异步的,需要一些时间来完成其操作 我已经做了很多关于任务、线程和并行性的研究,但到目前为止我没有运气。问题是,即使尝试了下面所有的解决方案,结果总是一样的,它似乎一次只处理两个请求 尝试: ->在简单for循环中创建任务,并使用和不使用TaskCreationOptions.LongRunning设置启动任务 ->在简单for

我需要测试我们的应用程序中是否存在内存泄漏,并在处理请求时监视内存使用是否增加过多。 我正试图开发一些代码来同时调用我们的api/webservice方法。此api方法不是异步的,需要一些时间来完成其操作

我已经做了很多关于任务、线程和并行性的研究,但到目前为止我没有运气。问题是,即使尝试了下面所有的解决方案,结果总是一样的,它似乎一次只处理两个请求

尝试:

->在简单for循环中创建任务,并使用和不使用TaskCreationOptions.LongRunning设置启动任务

->在简单for循环中创建线程,并使用和不使用高优先级启动它们

->在简单for循环上创建操作列表并使用

Parallel.Foreach(list, options, item => item.Invoke)
->直接在并行For循环内运行(如下)

->使用和不使用选项和TaskScheduler运行TPL方法

->尝试使用不同的MaxParallelism和MaxThreads值

->也检查过了,但也没用。(我会错过什么吗?)

->在Stackoverflow中查看了一些其他帖子,但是我不知道如何正确地将它们转换为C。(我从来没有用过F#…)

(任务计划程序类取自)

以下是我的基本结构:

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;
            }
        }
   }
据我所知,服务器端没有限制。我对并行/多任务世界还比较陌生。还有别的办法吗?我错过什么了吗

(为了清晰起见,我简化了所有代码,我相信提供的代码足以描述上述场景。我也没有发布应用程序代码,但它只是一个简单的WinForms屏幕,用于调用和显示结果。如果任何代码与此相关,请让我知道,我也可以编辑和发布。)

提前谢谢

EDIT1:我查看了服务器日志,发现它在两个接一个地接收请求,所以这确实与发送请求有关,而不是接收请求。 这可能是与框架如何管理请求/连接相关的网络问题/限制吗?还是网络上的什么东西(与.net无关)

EDIT2:忘了提一下,这是一个SOAP Web服务

EDIT3:我发送的属性之一(内部数据)需要为每个请求更改


EDIT4:我注意到,如果相关的话,每对请求之间总是有大约25秒的间隔。

创建负载测试而不编写自己的项目的一个好方法是使用此服务


它是免费的小测试,你可以张贴参数,标题,。。。而且您有一个很好的报告。

创建负载测试而不编写自己的项目的一个很好的解决方案是使用此服务


它是免费的小测试,你可以张贴参数,标题,。。。您的报告也不错。

我建议您不要重新发明轮子,而只使用现有的解决方案之一:

  • 最明显的选择:如果您的Visual Studio许可证允许您使用MS Load Testing Framework,则很可能您甚至不必编写一行代码:
  • 是一个免费的开源web服务测试工具,它有一些局限性
  • 如果由于某些原因SoapUI不适合(即,您需要从多个主机以集群模式运行负载测试,或者需要更多增强的报告),您可以使用免费的开源多协议负载测试工具,该工具也支持
    我建议不要重新发明轮子,只使用现有的解决方案之一:

  • 最明显的选择:如果您的Visual Studio许可证允许您使用MS Load Testing Framework,则很可能您甚至不必编写一行代码:
  • 是一个免费的开源web服务测试工具,它有一些局限性
  • 如果由于某些原因SoapUI不适合(即,您需要从多个主机以集群模式运行负载测试,或者需要更多增强的报告),您可以使用免费的开源多协议负载测试工具,该工具也支持 “一次两个请求”不是默认的连接管理maxconnection=2限制的结果吗

    <configuration>  
      <system.net>  
        <connectionManagement>  
          <add address = "http://www.contoso.com" maxconnection = "4" />  
          <add address = "*" maxconnection = "2" />  
        </connectionManagement>  
      </system.net>  
    </configuration> 
    
    
    
    一次两个请求不是默认maxconnection=2连接管理限制的结果吗

    <configuration>  
      <system.net>  
        <connectionManagement>  
          <add address = "http://www.contoso.com" maxconnection = "4" />  
          <add address = "*" maxconnection = "2" />  
        </connectionManagement>  
      </system.net>  
    </configuration> 
    
    
    
    您是否尝试过使用密码?您可以录制一个特定的请求,然后将此运行作为的一部分。谢谢,我没有尝试过,我将查看它。但是我只需要测试webmethod,没有UI。使用Web测试可以实现这一点吗?有可能同时运行很多次吗?因为我需要请求同时到达服务器,或者尽可能接近服务器。当然,如果WebMethod有HTTP端点,您可以使用Web测试记录请求(例如数据发布)。然后,您可以配置负载测试,比如说,50个并行用户10分钟,思考时间真实。我同意其他建议,使用工具/服务,而不是自己构建工具/服务。我使用JMeter,它是开源的,高度可配置的,还支持并行请求。您可以通过GUI或headless运行它,以满足您的需要。-问题是,我们的一些客户开发了基于我们的Web服务的系统集成,我试图模拟他们通常调用它的方式。我能用这些工具实现吗?因为我不仅需要发送请求,还需要检查它的返回并分析它,因为它有不同的返回代码和描述。例如,它可能返回一些消息,通知业务逻辑失败、完整代码/消息成功、异常(例如OutOfMemoryException)等。您是否尝试过使用?您可以记录一个特定的请求,然后将此作为运行的一部分。谢谢,我没有
    <configuration>  
      <system.net>  
        <connectionManagement>  
          <add address = "http://www.contoso.com" maxconnection = "4" />  
          <add address = "*" maxconnection = "2" />  
        </connectionManagement>  
      </system.net>  
    </configuration>