dsp*_*099 17 c# user-interface multithreading visual-studio-2010 task-parallel-library
更多新手问题:
这段代码从主窗口的列表中抓取了许多代理(我无法弄清楚如何在不同的函数之间使变量可用)并检查每个代理(简单的httpwebrequest),然后将它们添加到名为的列表中finishedProxies.
出于某种原因,当我按下开始按钮时,整个程序挂起.我的印象是Parallel为每个动作创建单独的线程,只留下UI线程,以便它响应?
private void start_Click(object sender, RoutedEventArgs e)
{
// Populate a list of proxies
List<string> proxies = new List<string>();
List<string> finishedProxies = new List<string>();
foreach (string proxy in proxiesList.Items)
{
proxies.Add(proxy);
}
Parallel.ForEach<string>(proxies, (i) =>
{
string checkResult;
checkResult = checkProxy(i);
finishedProxies.Add(checkResult);
// update ui
/*
status.Dispatcher.Invoke(
System.Windows.Threading.DispatcherPriority.Normal,
new Action(
delegate()
{
status.Content = "hello" + checkResult;
}
)); */
// update ui finished
//Console.WriteLine("[{0}] F({1}) = {2}", Thread.CurrentThread.Name, i, CalculateFibonacciNumber(i));
});
}
Run Code Online (Sandbox Code Playgroud)
我已经尝试使用已注释掉的代码来更改Parallel.Foreach中的UI,它会在按下启动按钮后冻结程序.它之前对我有用,但我使用的是Thread类.
如何从Parallel.Foreach内部更新UI,如何使Parallel.Foreach工作,以便它在工作时不会使UI冻结?
Jon*_*Jon 19
您不能在UI线程中启动并行处理.请参阅此页面中 "避免在UI线程上执行并行循环"标题下的示例.
更新:或者,你可以简单地创建一个新的线程manuall并开始内部处理,就像我看到你做的那样.这也没有错.
另外,正如Jim Mischel指出的那样,您同时从多个线程访问列表,因此存在竞争条件.无论是替代ConcurrentBag的List,或包裹列出了内lock声明每次访问他们的时间.
避免在使用Parallel语句时无法写入UI线程的问题的好方法是使用Task Factory和委托,请参阅以下代码,我使用它来迭代目录中的一系列文件,以及在并行的foreach循环中处理它们,在处理每个文件之后,UI线程被发信号通知并更新:
var files = GetFiles(directoryToScan);
tokenSource = new CancellationTokenSource();
CancellationToken ct = tokenSource.Token;
Task task = Task.Factory.StartNew(delegate
{
// Were we already canceled?
ct.ThrowIfCancellationRequested();
Parallel.ForEach(files, currentFile =>
{
// Poll on this property if you have to do
// other cleanup before throwing.
if (ct.IsCancellationRequested)
{
// Clean up here, then...
ct.ThrowIfCancellationRequested();
}
ProcessFile(directoryToScan, currentFile, directoryToOutput);
// Update calling thread's UI
BeginInvoke((Action)(() =>
{
WriteProgress(currentFile);
}));
});
}, tokenSource.Token); // Pass same token to StartNew.
task.ContinueWith((t) =>
BeginInvoke((Action)(() =>
{
SignalCompletion(sw);
}))
);
Run Code Online (Sandbox Code Playgroud)
以及实际UI更改的方法:
void WriteProgress(string fileName)
{
progressBar.Visible = true;
lblResizeProgressAmount.Visible = true;
lblResizeProgress.Visible = true;
progressBar.Value += 1;
Interlocked.Increment(ref counter);
lblResizeProgressAmount.Text = counter.ToString();
ListViewItem lvi = new ListViewItem(fileName);
listView1.Items.Add(lvi);
listView1.FullRowSelect = true;
}
private void SignalCompletion(Stopwatch sw)
{
sw.Stop();
if (tokenSource.IsCancellationRequested)
{
InitializeFields();
lblFinished.Visible = true;
lblFinished.Text = String.Format("Processing was cancelled after {0}", sw.Elapsed.ToString());
}
else
{
lblFinished.Visible = true;
if (counter > 0)
{
lblFinished.Text = String.Format("Resized {0} images in {1}", counter, sw.Elapsed.ToString());
}
else
{
lblFinished.Text = "Nothing to resize";
}
}
}
Run Code Online (Sandbox Code Playgroud)
希望这可以帮助!
| 归档时间: |
|
| 查看次数: |
20941 次 |
| 最近记录: |