我需要测试我们的应用程序和监视器中是否存在任何内存泄漏,以查看在处理请求时内存使用量是否增加太多。 我正在尝试开发一些代码来同时调用我们的api / webservice方法。这种api方法不是异步的,需要一些时间来完成其操作。
我对任务,线程和并行进行了大量研究,但到目前为止我没有运气。问题是,即使在尝试了以下所有解决方案之后,结果总是相同的,它似乎当时只处理两个请求。
尝试:
- >在一个简单的for循环中创建任务,并使用TaskCreationOptions.LongRunning
设置和创建任务- >在简单的for循环中创建线程并使用和不使用高优先级启动它们
- >在简单的for循环上创建操作列表并使用
启动它们Parallel.Foreach(list, options, item => item.Invoke)
- >直接在Parallel.For循环中运行(下面)
- >使用和不使用Options和TaskScheduler运行TPL方法
- >尝试使用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无关)?
EDIT2:忘记提及,它是一个SOAP Web服务。
EDIT3:我发送的一个属性(内部数据)需要针对每个请求进行更改。
EDIT4:我注意到,如果它们相关,那么每对请求之间的间隔总是约为25秒。
答案 0 :(得分:2)
我建议不要重新发明轮子,只使用现有的解决方案之一:
答案 1 :(得分:1)
在不编写自己的项目的情况下创建负载测试的好方法是使用此服务https://loader.io/targets
对于小型测试,它是免费的,你可以POST参数,标题,...并且你有一个很好的报告。
答案 2 :(得分:0)
默认的maxconnection = 2限制connectionManagement的结果是“一次两个请求”吗?
<configuration>
<system.net>
<connectionManagement>
<add address = "http://www.contoso.com" maxconnection = "4" />
<add address = "*" maxconnection = "2" />
</connectionManagement>
</system.net>
</configuration>