【发布时间】:2017-03-17 19:09:10
【问题描述】:
我有一个函数可以修改我的列表视图“inputList”,列表视图有 5 列。该功能应该检查列表视图中的单元格,如果没有问题,最后一列中的单元格将具有绿色背景的“NORMAL”,如果有问题,它将在单元格中显示带有红色背景的“ERROR”在最后一列中,并更改其他列中同一行中错误单元格的颜色。
有 4k 个项目,我知道拥有这么多项目毫无意义,因为用户不会阅读它们,但我被要求这样做。
我正在使用带有 backgroundworker 的函数,但它不够快,并且认为 parallelFor 会更快。但是当我尝试使用parallelFor时,它会冻结程序。
这是带有 backgroundworker 的函数,它正在工作但它太慢了:
private void bw3_DoWork(object sender, DoWorkEventArgs e)
{
String tempTrain = "";
String tempPredic = "";
String tempNet = "";
Boolean bTrain;
Boolean bPredic;
Boolean bNetErro;
int n;
int nNet = 0;
String tTrain = "";
String tPredic = "";
int nList = 0;
this.Invoke(new MethodInvoker(() => {
nList = inputList.Items.Count;
nNet = menuNetwork.Items.Count;
tTrain = dtrainTextBox.Text;
tPredic = dpredicTextBox.Text;
}));
for (int i = 0; i < nList; i++)
{
ListViewItem.ListViewSubItem temp1 = new ListViewItem.ListViewSubItem();
temp1.BackColor = Color.LightGreen;
temp1.Text = "NORMAL";
this.Invoke(new MethodInvoker(() =>
{
inputList.Items[i].SubItems[0].BackColor = Color.White;
inputList.Items[i].SubItems[1].BackColor = Color.White;
inputList.Items[i].SubItems[2].BackColor = Color.White;
tempTrain = String.Format("{0}\\{1}", tTrain, inputList.Items[i].SubItems[1].Text);
tempPredic = String.Format("{0}\\{1}", tPredic, inputList.Items[i].SubItems[2].Text);
tempNet = (String)inputList.Items[i].SubItems[0].Tag;
}));
bTrain = (!File.Exists(tempTrain));
bPredic = (!File.Exists(tempPredic));
bNetErro = !(int.TryParse(tempNet, out n));
if (!bNetErro)
{
if (!(n < nNet))
{
bNetErro = true;
}
}
this.Invoke(new MethodInvoker(delegate
{
if (bTrain) inputList.Items[i].SubItems[1].BackColor = Color.Red;
if (bPredic) inputList.Items[i].SubItems[2].BackColor = Color.Red;
if (bNetErro) inputList.Items[i].SubItems[0].BackColor = Color.Red;
if (bTrain | bPredic | bNetErro) { temp1.Text = "Erro"; temp1.BackColor = Color.Red; }
try { inputList.Items[i].SubItems[4] = temp1; }
catch (ArgumentOutOfRangeException) { inputList.Items[i].SubItems.Add(temp1); }
}));
}
}
这是 ParallelFor 的功能,即使我尝试一个只有项目的非常小的示例,程序也会停止工作。
private void tent1()
{
ParallelOptions options = new ParallelOptions();
options.MaxDegreeOfParallelism = 4;
String tempTrain = "";
String tempPredic = "";
String tempNet = "";
String tTrain = dtrainTextBox.Text;
String tPredic = dpredicTextBox.Text;
Boolean bTrain;
Boolean bPredic;
Boolean bNetErro;
int n;
int nNet = networkList.Items.Count;
Parallel.For(0, inputList.Items.Count,
i =>
{
ListViewItem.ListViewSubItem temp1 = new ListViewItem.ListViewSubItem();
temp1.BackColor = Color.LightGreen;
temp1.Text = "NORMAL";
Console.WriteLine(i);
this.Invoke(new MethodInvoker(() =>
{
inputList.Items[i].SubItems[0].BackColor = Color.White;
inputList.Items[i].SubItems[1].BackColor = Color.White;
inputList.Items[i].SubItems[2].BackColor = Color.White;
tempTrain = String.Format("{0}\\{1}", tTrain, inputList.Items[i].SubItems[1].Text);
tempPredic = String.Format("{0}\\{1}", tPredic , inputList.Items[i].SubItems[2].Text);
tempNet = (String)inputList.Items[i].SubItems[0].Tag;
}));
bTrain = (!File.Exists(tempTrain));
bPredic = (!File.Exists(tempPredic));
bNetErro = !(int.TryParse(tempNet, out n));
if (!bNetErro)
{
if (!(n < nNet))
{
bNetErro = true;
}
}
this.Invoke(new MethodInvoker(delegate
{
if (bTrain) inputList.Items[i].SubItems[1].BackColor = Color.Red;
if (bPredic) inputList.Items[i].SubItems[2].BackColor = Color.Red;
if (bNetErro) inputList.Items[i].SubItems[0].BackColor = Color.Red;
if (bTrain | bPredic | bNetErro) { temp1.Text = "Erro"; temp1.BackColor = Color.Red; }
try { inputList.Items[i].SubItems[4] = temp1; }
catch (ArgumentOutOfRangeException) { inputList.Items[i].SubItems.Add(temp1); }
}));
});
}
如何在不参考的情况下将列表视图的所有项目复制到列表中?我认为直接在列表视图中添加/修改,并且调用会减慢函数的速度,因此创建:List<ListViewItem> tList
我会修改 tList 中的所有内容,然后我会使用 inputList.Items.AddRange(tList.ToArray());
这将删除循环内的所有调用。
ListViewItem[] tItemsTemp = null;
this.Invoke(new MethodInvoker(() =>
{
tItemsTemp = new ListViewItem[inputList.Items.Count];
inputList.Items.CopyTo(tItemsTemp, 0);
nList = inputList.Items.Count;
nNet = menuNetwork.Items.Count;
tTrain = dtrainTextBox.Text;
tPredic = dpredicTextBox.Text;
}));
List<ListViewItem> tList = new List<ListViewItem>(tItemsTemp);
ListViewItem[] tItems = (ListViewItem[]) tItemsTemp.Clone();
//Modifies the list or array of listviewitems
this.Invoke(new MethodInvoker(delegate
{
inputList.Items.Clear();
// Just one of them,not the 3,just showing how i would call them.
inputList.Items.AddRange(tItems);
inputList.Items.AddRange(tItemsTemp);
inputList.Items.AddRange(tList.ToArray());
}));
但是 tItemsTemp,tItems,tList 都是引用... 如何通过创建参考进行复制?
【问题讨论】:
-
"不够快" "冻结程序" "正在运行";这些都是非常模糊的术语,你没有问任何问题。有什么问题?你得到什么?你在期待什么?你试过什么?您是否从这些帖子中搜索过类似内容并尝试过建议?
-
这和你之前的问题有关。它看起来仍然在进行大量的 GUI 工作。为什么不试试这个:停止使用 BackgroundWorker 并分析您的代码以查看 哪个部分 是耗时的部分。现在,您只是在后台线程中投掷飞镖,希望它能加快速度。这很少奏效。我猜你最好在更新所有内容之前关闭控件的绘图。
-
如果没有可靠地重现问题的a good, minimal, complete code example,就不可能确定问题出在哪里。但是,根据此处显示的少量代码,您似乎可能已经死锁了 GUI 线程(即通过从那里调用
Parallel.For()),或者您正在重载它(即通过大量调用在短时间内到Invoke())。无论哪种方式,请改进问题以便回答。 -
@sab669 程序停止工作,但未显示任何错误/异常。速度不够快是因为耗时太长。
-
用更多细节编辑了问题。
标签: c# winforms listview visual-studio-2013 parallel.for