提问人:Gabriele Troviso 提问时间:11/17/2023 最后编辑:EnigmativityGabriele Troviso 更新时间:11/21/2023 访问量:69
如何在 C 中创建一对一的多线程关系和处理异常#
How to create one-to-one multithreading relationship and handling exception in C#
问:
这是我第一次在多线程应用程序上工作(一般来说,不仅仅是 C#),因此我只知道关于它的简单概念。我已经实现了基本上使用命名空间实现。System.Threading
我有一个字典,它将对象 A 与其 ID () 链接起来。每个 A 都必须执行一个操作(每个 A 都执行相同的操作),我希望此操作在单独的线程列表中工作,每个 A 一个。Dictionary<int,A>
我知道这是实现多线程的糟糕方法,但我目前只知道这个命名空间。我做了一些事情:System.Threading
public class ThreadManager
{
private Dictionary<int, A> _aList;
public Dictionary<int, A> AList
{
get { return _aList; }
set { _aList = value; }
}
private Dictionary<int, Thread> _threadList;
public Dictionary<int, Thread> ThreadList
{
get { return _threadList; }
set { _threadList = value; }
}
public ThreadManager(Dictionary<int, A> list)
{
AList = list;
ThreadList = new Dictionary<int, Thread>();
foreach (A a in AList)
{
int id = a.Id;
ThreadList.Add(id, new Thread(new ParameterizedThreadStart(Operation)));
}
}
public void Operation(object data)
{
try
{
/*** do something***/
}
catch (Exception e)
{
/*** throw exception ***/
}
}
}
当我在应用程序代码的外部运行特定线程时:
ThreadManager.ThreadList[i].Start(data)
做必要的操作似乎工作正常。但是,我认为这个解决方案真的很丑陋,而且功能不是很强大。
此外,还有另一个大问题。当 throw 中出现异常时,正如预期的那样,它不会从线程中捕获。我可以在代码的另一个点中捕获线程异常,这些异常适用于不同的线程(例如主线程)吗?
编辑:
为了清楚起见,我希望没有线程阻塞主线程。我需要能够在操作工作时对主线程进行操作。
答:
我建议它使用 async/await 的组合,并且:Task.Run
Parallel.ForEach
private async void button1_Click(object sender, EventArgs e)
{
try
{
Cursor = Cursors.WaitCursor;
button1.Enabled = false;
await Task.Run(() =>
{
ParallelOptions options = new()
{
MaxDegreeOfParallelism = Environment.ProcessorCount
};
Parallel.ForEach(dictionary, options, entry =>
{
var (key, value) = entry;
/* do something with the key and value */
});
});
}
catch (AggregateException aex)
{
/* handle aex.InnerExceptions (can be more than one) */
}
finally
{
button1.Enabled = true;
Cursor = Cursors.Default;
}
}
- 使用
async
和await
关键字可以编写不会阻塞 UI 线程的异步代码,就像编写普通同步代码一样。当异步操作在进行中时,UI 保持响应。 Task.Run
将委托的处理卸载到ThreadPool
线程。是由 .NET 基础结构管理的可重用线程池。如有必要,可以使用ThreadPool.SetMinThreads
方法对其进行微调。action
ThreadPool
Parallel.ForEach
在多个线程上并行调用委托,从而强制执行MaxDegreeOfParallelism
策略。如果您想要无限的并行性,请使用 .body
ThreadPool
MaxDegreeOfParallelism = -1
如果发生异常,将停止调用委托,并在所有当前正在运行的调用完成后完成。所有错误调用的错误都将捆绑在 AggregateException
中。此异常将首先由 传播,然后由运算符传播,您将能够在 UI 线程上使用事件处理程序中的 / 块处理它。您也可以让它不处理(省略块),在这种情况下,它将作为常规 Application.ThreadException
事件处理程序进行处理。如果也省略了这一点,则 WinForms 应用程序默认显示的默认错误弹出窗口将通知用户,并为用户提供继续或退出应用程序的选项。Parallel.ForEach
body
Task.Run
await
try
catch
Click
catch
评论
DynamicParallelOptions.DegreeOfParallelism
if (value < 1)
if (value < 0)
评论
Parallel.ForEach()
foreach (A a in AList)
<-- 这无法编译。await Task.WhenAll(listOfTasks)