c# - 四个循环使用两个范围来找到最高 PNL
问题描述
我试图让这段代码运行得更快,因为它有数十亿种组合。我需要查看四个循环,并根据这些参数找到最高的利润。字典可能有 500 条记录,我通常使用 excel 来查找表现最好的设置的模式,几分钟后我最终得到了大约 100 个条目。你们认为哪种方法最适合我,或者您有什么建议?
using System;
using System.Collections.Concurrent;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.Windows.Forms;
namespace WindowsFormsApp1 {
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
}
public class Stock {
public double PNL { get; set; }
public double OD { get; set; }
public double DR { get; set; }
public double Volume { get; set; }
public double Liquidity { get; set; }
public Stock(double iPNL, double iOD, double iDR, double iVolume, double iLiquidity) {
PNL = iPNL;
OD = iOD;
DR = iDR;
Volume = iVolume;
Liquidity = iLiquidity;
}
}
private ConcurrentDictionary<string, Stock> StockData = new();
private void button1_Click(object sender, EventArgs e) {
StockData["A"] = new Stock(-109, 60, 0.92, 32, 5.99);
StockData["B"] = new Stock(41, 25, 0.96, 37, 6.75);
StockData["C"] = new Stock(41, 62, 1.12, 79, 8.4);
long iLoops = 0;
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
double iODMax = 999;
double iDRMax = 1500;
double iVolMax = 999;
double iLiqMax = 2000;
double PNL = 0;
for (int iODMin = 0; iODMin <= iODMax; iODMin += 6) {
for (double iDRMin = 1; iDRMin <= iDRMax; iDRMin += 6) {
for (int iVolMin = 0; iVolMin <= iVolMax; iVolMin += 6) {
for (double iLiqMin = 1; iLiqMin <= iLiqMax; iLiqMin += 6) {
iLoops += 1;
var aaaa = StockData.Where(n => n.Value.OD >= iODMin && n.Value.OD <= iODMax &&
n.Value.DR >= iDRMin && n.Value.DR <= (iDRMax / 100) &&
n.Value.Liquidity >= iLiqMin && n.Value.Liquidity <= (iLiqMax / 100) &&
n.Value.Volume >= iVolMin && n.Value.Volume <= iVolMax).FirstOrDefault();
if (aaaa.Value != null) {
PNL += aaaa.Value.PNL;
}
}
}
}
}
stopwatch.Stop();
Debug.Print(stopwatch.Elapsed.ToString() + " | " + iLoops.ToString("#,#") + " | " + PNL.ToString("#,#"));
}
}
}
解决方案
这是您可以在逻辑中实现并行性的一种方法,它可以为您提供更好的性能。
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
public class Stock
{
public double PNL { get; set; }
public double OD { get; set; }
public double DR { get; set; }
public double Volume { get; set; }
public double Liquidity { get; set; }
public Stock(double iPNL, double iOD, double iDR, double iVolume, double iLiquidity)
{
PNL = iPNL;
OD = iOD;
DR = iDR;
Volume = iVolume;
Liquidity = iLiquidity;
}
}
private ConcurrentDictionary<string, Stock> StockData = new ConcurrentDictionary<string, Stock>();
public IEnumerable<int> SteppedIntegerList(int startIndex,
double endEndex, int stepSize)
{
for (int i = startIndex; i < endEndex; i += stepSize)
{
yield return i;
}
}
object lockObject = new object();
private void button1_Click(object sender, EventArgs e)
{
StockData["A"] = new Stock(-109, 60, 0.92, 32, 5.99);
StockData["B"] = new Stock(41, 25, 0.96, 37, 6.75);
StockData["C"] = new Stock(41, 62, 1.12, 79, 8.4);
long iLoops = 0;
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
double iODMax = 499;
double iDRMax = 1000;
double iVolMax = 499;
double iLiqMax = 1500;
double PNL = 0;
Parallel.ForEach(SteppedIntegerList(0, iODMax, 6), iODMin =>
{
Parallel.ForEach(SteppedIntegerList(1, iDRMax, 6), iDRMin =>
{
Parallel.ForEach(SteppedIntegerList(0, iVolMax, 6), iVolMin =>
{
Parallel.ForEach(SteppedIntegerList(1, iLiqMax, 6), iLiqMin =>
{
Interlocked.Increment(ref iLoops);
var aaaa = StockData.Where(n => n.Value.OD >= iODMin && n.Value.OD <= iODMax &&
n.Value.DR >= iDRMin && n.Value.DR <= (iDRMax / 100) &&
n.Value.Liquidity >= iLiqMin && n.Value.Liquidity <= (iLiqMax / 100) &&
n.Value.Volume >= iVolMin && n.Value.Volume <= iVolMax).FirstOrDefault();
if (aaaa.Value != null)
{
lock (lockObject)
{
PNL += aaaa.Value.PNL;
}
}
});
});
});
});
stopwatch.Stop();
Debug.Print(stopwatch.Elapsed.ToString() + " | " + iLoops.ToString("#,#") + " | " + PNL.ToString("#,#"));
}
}
//输出分析
我已经减少了下面提到的样本数据来测试我自己的目的
double iODMax = 499;
double iDRMax = 1000;
double iVolMax = 499;
double iLiqMax = 1500;
有了上面的数据出来是这样的:
// 你给出的逻辑:00:03:44.7069770 | 294,588,000 | 12,628
// 具有并行性的新逻辑:00:01:13.9397930 | 294,588,000 | 12,628
我需要引入对象锁定,因为这些是所有线程之间的共享资源,因此您可以相应地扩展您的逻辑。
有关Parallel.For的更多信息
推荐阅读
- graphql - 如何修复 EntitySchema 和 Graphql 中的“无法读取未定义的属性“joinColumns”错误
- ffmpeg - ffmpeg 使用 -filter_complex 修复不能被 2 (401x480) 整除
- javascript - 如何在下面的字段中自动生成选定的选项 ID?
- c# - 我无法从视图中保存结果变量
- python - 如何在 QTablewidget 列的列上应用验证器?
- python - Python 中的 ModuleNotFoundError
- python - 从列中选择的数值的平均值
- html - CSS - 如何为子元素应用 css plus 选择器
- javascript - 如何在javascript中获取动态加载图像的宽度和高度?
- c++ - C++ STL中set的'insert'函数的原理是什么?