您将为开发多线程应用程序的人提供哪些提示?
我唯一能想到的是:
可以避免的情况是,没有多个线程写入相同的数据结构。
如果无法避免这种情况,请使用关键部分,以便后续线程等到完成为止。
避免使用除常量之外的全局变量。
确保线程在完成后立即释放资源。
有人能想到别的什么吗?
答案 0 :(得分:2)
考虑到问题的广度(或含糊不清),我建议你在Joe Duffy上获取一份Windows并发编程,ISBN:978-0-321-43482-1
答案 1 :(得分:1)
多线程是一个非常复杂的问题 - 我最大的建议是:
那就是说,我真的相信多线程没有什么根本性的困难,只是很多程序员都习惯于单线程编程,他们做出的假设在多线程环境中是无效的。如果你是多线程的新手,那么你应该非常谨慎地接受它,不过你已经习惯了它。
答案 2 :(得分:0)
如果锁定多个对象,请尝试始终以相同的顺序锁定它们。这应该可以最大限度地减少您遇到的死锁。
答案 3 :(得分:0)
基本建议:
设计和规划
- 花一些时间准确理解应该执行的内容,确定优先级以及在异步模式下可以完成的任务
资源控制
- 使用一种有效的方法来控制共享资源,关键部分是一种很好的方法
避免重新创建线程
- 线程的使用带来效率和性能
优先考虑活动
-log记录必须由特定的线程为此目的进行,因此核心不会浪费时间
答案 4 :(得分:0)
我多年来一直致力于开发多线程应用程序。在我相信自己掌握了一些主题之前,它总是令人惊讶。今年对我来说将是多线程的一年。
以下是我的多线程提示:
不要编写多线程应用程序。如果可能,请远离它。回到COM的时代,你必须为对象选择你的线程模型,并且在几乎所有情况下,最好给每个线程都有自己的内存和对象来处理。什么也没有变。多线程应用程序比单线程应用程序更复杂。它们与1995年一样困难和混乱。所有协助多线程处理的高级对象都无法保护您免受您所邀请的逻辑复杂性的增加。
隔离您的共享对象。如果您必须编写多线程应用程序,请了解多线程的唯一重大挑战是对同一对象的并发更新。还有其他小问题,但这是最重要的问题。
想象一下友好的线程在你身边执行。如果您在Web服务器上的UpdatePerformers函数中并且您正在编码: 如果(!List.Contains(表演者)) {List.Add(performer)}
a. Imagine another thread executing on exactly the same line.
b. On the line before or after
c. Entering the function
获得锁定后,检查是否仍需要执行任何操作。
If (!Game.IsFinalized){
Lock(Game) {
If (!Game.IsFinalized)
FinalizeGame(Game)}
一个。在获取锁定后的行上,再次为IsFinalized测试游戏,因为它被OFTEN锁定,因为另一个线程已经获得了完全相同的锁定。
湾或者,如果这是您的约定,请在调用函数之前检查Game.IsFinalized是否在开始工作之前。请务必检查。
假设什么都不是线程安全的!线程安全通常以性能为代价,或者它通常定义对象功能的限制或不必要的复杂性......因此大多数对象都不是线程安全的。不要想,"但我使用最新,最好的框架!"它不是线程安全的。实体框架不是线程安全的。
ConcurrentCollections在.NET中很棒。你会注意到那里没有" List"在命名空间中。 ConcurrentLists更加棘手,因为随机插入多线程编号列表是模糊的和/或不可能的。堆栈,队列,包和词典通常都很好。相应地计划。
在长迭代中,在迭代之前复制列表。如果您在对其进行迭代时对其进行修改,则可能是您的逻辑错误...但有时最好锁定列表,创建浅层副本(ToList()并迭代它。
在.NET中,Task对象值得一试。他们非常适合排队连续工作。锁通常很好,可以非常简单和紧凑。
如果程序中没有资源获取延迟,则线程数应尝试匹配处理器数。如果您有一台四核计算机,则在应用程序中运行四个以上线程的唯一原因是该场景需要线程在获取资源时进入等待状态。线程上下文切换很昂贵。
创建线程的成本相当高。如果您按需按需旋转并经常销毁它们,则开销可能相当大。使用线程池。
不要意外锁定非静态对象。我曾多次犯过这个错误:私有对象_lockGameUpdate在Web服务上。每次调用都使用Web服务对象的新副本,因此文件中的lock(_lockGameUpdate)实际上不会执行任何操作。由于您经常仅使用锁定变量来锁定,因此很容易误解它们。私有STATIC对象_lockGameUpdate,当然,按预期工作。
测试期间,测试: 一个。一堆线程同时开始 湾交错创建线程 C。从具有完全相同参数的单独线程进行双重调用。
Visual Studio
您可以控制断点是暂停所有线程还是仅暂停中断线程。在条件断点中,您可以放置Thread = {ThreadId}以确保您没有调试的其他线程不会进入您的断点。
你可以冻结另一个线程。在线程窗口中执行此操作。选择所有线程"通常很有用。 (ctrl-a),然后取消选择要调试的线程,然后单击"冻结线程"隔离你的调试。
命名你的主题。您给出的名称会显示在线程窗口中。
良好的日志记录至关重要。多线程对调试器造成严重破坏,特别是在评估变量时。
只是一个补充说明。我们在数据库行和表锁定中处理的问题正是我们在多线程资源共享/锁定方面取得的进展。所有的想法,如悲观和乐观的锁定以及数据库如何在内部进行交易,如果理解得好......是一种多线程掌握本身的形式。您在SQL Server锁定和并发中的决策中找到的所有想法和性能权衡只是在不同的域中进行多线程处理。
多线程的难点不是基于框架或语法。它基于LOGIC,因此任何像数据库这样的并发解决系统都被迫解决完全相同的LOGICAL问题。如果你有这样的经验可以这样想的话就这么想。
答案 5 :(得分:-1)
使用行级锁定。
使用TRANSACTION_READ_COMMITTED隔离级别。
避免无法使用索引的查询;它们需要锁定表中的所有行(如果只是非常短暂地)并且可能阻止更新。