【发布时间】:2017-07-20 14:03:23
【问题描述】:
首先谈谈我的目标:
我正在将一个包含大约 1000-5000 行的表导入到 DataTable。这个绑定到DataGridView。现在对于每一行都必须运行一个大约需要 5-10 秒的过程。单个进程完成后,我想将结果写回DataTabel(结果列)。
因为这个过程是独立的,所以我想使用多线程来加速它。
这是我当前代码的示例结构:
// Will be created for each row
public class FooObject
{
public int RowIndex;
public string Name;
//...
}
// Limiting running tasks to 50
private Semaphore semaphore = new Semaphore(50, 50);
// The DataTable is set up at start-up of the App (columns etc)
private DataTable DtData { get; set; } = new DataTable();
// The button that starts the process
private void btnStartLongRun(object sender, EventArgs e)
{
// some init-stuff
StartRun();
}
private async void StartRun()
{
for (int rowIndex = 0; rowIndex < DtData.Rows.Count)
{
// Creating a task to not block the UI
// Using semaphore here to not create objects
// for all lines before they get in use.
// Having this inside the real task it consumed
// a lot of ram (> 1GB)
await Task.Factory.StartNew(() =>
{
semaphore.WaitOne();
});
// The row to process
var currentRow = DtData.Rows[rowIndex];
// Creating an object from the row-data
FooObject foo = new FooObject()
{
RowIndex = rowIndex;
Name = currentRow["Name"].ToString();
}
// Not awaiting because I want multiple threads
// to run at the same time. The semaphore is
// handling this
TaskScheduler scheduler = TaskScheduler.Current;
Task.Factory.StartNew(() =>
{
// Per-row process
return ProcessFoo(foo);
}).ContinueWith((result) =>
{
FinishProcessFoo(result.Result);
}, CancellationToken.None, TaskContinuationOptions.OnlyOnRanToCompletion, scheduler);
}
}
private FooObject ProcessFoo(FooObject foo)
{
// the actual big process per line
}
private void FinishProcessFoo(FooObject foo)
{
// Locking here because I got broken index errors without
lock(DtGrid.Rows.SyncRoot)
{
// Getting the row that got processed
var procRow = DtData.Rows[foo.RowIndex];
// Writing the result to that row
procRow["Result"] = foo.Result;
// Raising the progressbar
pbData.Value++;
}
// Letting the next task start.
semaphore.Release();
}
最大的问题:
一开始一切正常。所有线程都运行顺利并完成他们的工作。但是,随着应用程序运行的时间越长,它越会变得无响应。看起来该应用正在慢慢开始越来越多地被阻止。
我开始了 5000 行的测试运行。它卡在第 2000 行左右。有时甚至会引发the app isn't responding 的错误。
我在多线程方面没有太多经验。所以也许这段代码完全不好。我感谢这里的每一个帮助。我也很乐意为我指出另一个方向以使其运行得更好。
非常感谢。
编辑
如果有什么我可以调试的,请告诉我。
编辑 2
我已经启用了所有 Common Language Runtime Exceptions 以检查是否有任何未引发错误的内容。什么都没有。
【问题讨论】:
-
如果您想并行处理项目,为什么不简单地使用 Parallel.For?:docs.microsoft.com/en-us/dotnet/standard/parallel-programming/…
-
因为我不能限制线程对吧?如果并行抛出所有行,应用程序将立即创建 5000 个对象,最终会消耗大量内存。也许我错了。但这就是我的想法。
-
我不希望它们同时运行。必须有一个限度。 5000实在是太多了。我还需要写回结果。我想我需要并行调用控件。
-
您可以使用 ParallelOptions.MaxDegreeOfParallelism 属性:stackoverflow.com/questions/9538452/…
标签: c# multithreading winforms task semaphore