一、综述

《Effective C#》中提高多线程性能的方法主要有以下几点:

  1. 避免锁竞争:锁的使用会导致线程阻塞,从而影响程序的性能。为了避免锁竞争,可以采用无锁编程技术,如CAS(Compare-And-Swap),Interlocked 等。

  2. 使用 Thread Pool:Thread Pool 是 .NET Framework 提供的一个线程池,它可以管理线程的创建与销毁,并且可以重复利用线程,从而提高程序的性能。建议使用 ThreadPool 来代替手动创建和销毁线程。

  3. 使用 Task Parallel Library(TPL):TPL 是 .NET Framework 提供的一种并行计算库,它可以自动管理线程的创建和销毁,并且可以智能地分配任务给线程池中的线程,从而提高程序的性能。

  4. 减少线程切换:线程上下文切换是非常耗费资源的操作,因此应该尽量减少线程切换的次数。可以通过减少线程睡眠时间、避免过度的 I/O 操作等方式来减少线程切换。

  5. 优化内存分配:在多线程程序中,频繁的内存分配和回收会导致垃圾回收器的频繁触发,从而造成性能瓶颈。可以采用对象池、缓存等方式来优化内存分配。

  6. 使用 Concurrent 集合:Concurrent 集合是 .NET Framework 提供的线程安全的集合类,它可以避免锁竞争和死锁等问题,从而提高程序的性能。

  7. 采用异步编程:异步编程可以避免线程阻塞,从而提高程序的性能。可以使用 async/await 关键字或者 Task 类来实现异步编程。

总之,《Effective C#》中提高多线程性能的方法主要是通过避免锁竞争、使用 Thread Pool 和 TPL 等技术来提高程序的效率。

二、提高多线程性能之避免锁竞争

1、避免锁竞争的具体技术要点

《Effective C#》中避免锁竞争的具体技术主要有以下几点:

  1. 无锁编程:无锁编程是一种基于原子操作和 CAS(Compare-And-Swap)等技术实现线程同步的方式,可以避免锁竞争和死锁等问题。下面是一个使用 Interlocked 类实现无锁计数器的示例代码:
public class Counter
{
private int count; public void Increment()
{
Interlocked.Increment(ref count);
} public void Decrement()
{
Interlocked.Decrement(ref count);
}
}
  1. ReaderWriterLock:ReaderWriterLock 是一种读写锁,它可以让多个线程同时读取共享资源,但只允许一个线程写入共享资源。这样可以有效地避免锁竞争和提高程序的性能。下面是一个使用 ReaderWriterLock 实现线程同步的示例代码:
public class Resource
{
private readonly ReaderWriterLockSlim rwLock = new ReaderWriterLockSlim();
private int value; public int ReadValue()
{
rwLock.EnterReadLock();
try
{
return value;
}
finally
{
rwLock.ExitReadLock();
}
} public void WriteValue(int newValue)
{
rwLock.EnterWriteLock();
try
{
value = newValue;
}
finally
{
rwLock.ExitWriteLock();
}
}
}
  1. Immutable 对象:Immutable 对象是指不可变的对象,它们的属性值在创建之后不会发生改变。由于 Immutable 对象是线程安全的,可以避免锁竞争和死锁等问题。下面是一个使用 Immutable 对象实现线程同步的示例代码:
public class Person
{
public string Name { get; }
public int Age { get; } public Person(string name, int age)
{
Name = name;
Age = age;
}
} public class ImmutableResource
{
private readonly Immutable<Person> person; public ImmutableResource(Person person)
{
this.person = Immutable.Create(person);
} public Person GetPerson()
{
return person.Value;
} public ImmutableResource UpdatePerson(Person newPerson)
{
return new ImmutableResource(newPerson);
}
}

总之,《Effective C#》中避免锁竞争的具体技术主要是通过无锁编程、ReaderWriterLock 和 Immutable 对象等方式来实现线程同步,从而提高程序的性能。

附录:多线程基础

多线程编程的技术要点包括线程的创建、同步、互斥、死锁等方面。

  1. 线程的创建

    在C#中,可以通过Thread类来创建一个新线程。例如:
using System;
using System.Threading; class Program
{
static void Main(string[] args)
{
Thread newThread = new Thread(DoWork);
newThread.Start();
} static void DoWork()
{
Console.WriteLine("New thread started!");
}
}

在这个例子中,我们创建了一个新的线程并启动了它,该线程会执行DoWork方法。

  1. 线程的同步

    当多个线程同时访问共享资源时,就需要进行线程同步。C#提供了多种同步机制,如锁、信号量、事件等。例如:
using System;
using System.Threading; class Program
{
static int count = 0;
static object lockObj = new object(); static void Main(string[] args)
{
Thread t1 = new Thread(Increment);
Thread t2 = new Thread(Increment); t1.Start();
t2.Start(); t1.Join();
t2.Join(); Console.WriteLine("Count: " + count);
} static void Increment()
{
for (int i = 0; i < 100000; i++)
{
lock (lockObj)
{
count++;
}
}
}
}

在这个例子中,我们创建了两个线程来并发地增加count变量的值。为了避免竞争条件,我们使用了lock关键字来锁定共享资源,确保每个线程在修改count变量时都能够独占它。

  1. 线程的互斥

    线程互斥是指多个线程之间相互排斥,只有一个线程能够访问共享资源。在C#中,可以使用Mutex类来实现线程互斥。例如:
using System;
using System.Threading; class Program
{
static int count = 0;
static Mutex mutex = new Mutex(); static void Main(string[] args)
{
Thread t1 = new Thread(Increment);
Thread t2 = new Thread(Increment); t1.Start();
t2.Start(); t1.Join();
t2.Join(); Console.WriteLine("Count: " + count);
} static void Increment()
{
for (int i = 0; i < 100000; i++)
{
mutex.WaitOne();
count++;
mutex.ReleaseMutex();
}
}
}

在这个例子中,我们使用Mutex类来实现线程互斥。在Increment方法中,我们首先调用WaitOne方法来请求锁定Mutex对象,然后修改count变量的值,最后调用ReleaseMutex方法来释放锁定。

  1. 线程的死锁

    线程死锁是指两个或多个线程互相等待对方释放锁定的资源,导致程序永远无法继续执行。为了避免线程死锁,需要遵循一些规则:
  • 避免嵌套锁定
  • 避免循环等待
  • 使用超时机制

例如:

using System;
using System.Threading; class Program
{
static object lock1 = new object();
static object lock2 = new object(); static void Main(string[] args)
{
Thread t1 = new Thread(() =>
{
lock (lock1)
{
Thread.Sleep(1000);
lock (lock2)
{
Console.WriteLine("Thread 1");
}
}
}); Thread t2 = new Thread(() =>
{
lock (lock2)
{
Thread.Sleep(1000);
lock (lock1)
{
Console.WriteLine("Thread 2");
}
}
}); t1.Start();
t2.Start(); t1.Join();
t2.Join();
}
}

在这个例子中,我们创建了两个线程,每个线程都锁定了两个共享资源。如果这两个线程同时运行,它们就会陷入死锁状态,因为每个线程都在等待对方释放锁定的资源。

《Effective C#》系列之(六)——提高多线程的性能的更多相关文章

  1. .NET面试题系列(六)多线程

    1.多线程的三个特性:原子性.可见性.有序性 原子性:是指一个操作是不可中断的.即使是多个线程一起执行的时候,一个操作一旦开始,就不会被其他线程干扰. 比如,对于一个静态全局变量int i,两个线程同 ...

  2. Redis总结(五)缓存雪崩和缓存穿透等问题 Web API系列(三)统一异常处理 C#总结(一)AutoResetEvent的使用介绍(用AutoResetEvent实现同步) C#总结(二)事件Event 介绍总结 C#总结(三)DataGridView增加全选列 Web API系列(二)接口安全和参数校验 RabbitMQ学习系列(六): RabbitMQ 高可用集群

    Redis总结(五)缓存雪崩和缓存穿透等问题   前面讲过一些redis 缓存的使用和数据持久化.感兴趣的朋友可以看看之前的文章,http://www.cnblogs.com/zhangweizhon ...

  3. 【微信小程序开发•系列文章六】生命周期和路由

    这篇文章理论的知识比较多一些,都是个人观点,描述有失妥当的地方希望读者指出. [微信小程序开发•系列文章一]入门 [微信小程序开发•系列文章二]视图层 [微信小程序开发•系列文章三]数据层 [微信小程 ...

  4. S3C2416裸机开发系列十六_sd卡驱动实现

    S3C2416裸机开发系列十六 sd卡驱动实现 象棋小子    1048272975 SD卡(Secure Digital Memory Card)具有体积小.容量大.传输数据快.可插拔.安全性好等长 ...

  5. Nginx知多少系列之(六)Linux下.NET Core项目负载均衡

    目录 1.前言 2.安装 3.配置文件详解 4.工作原理 5.Linux下托管.NET Core项目 6.Linux下.NET Core项目负载均衡 7.负载均衡策略详解 8.Linux下.NET C ...

  6. Http系列:断点续传与多线程下载

    前言 当下载电影时,我常常会想中断下载后,为什么点击开始时会在中断的地方继续下载呢?又或者在看在线电影时,为什么可以按着播放条拖动就能看到想看的片段呢? http的range请求将解决以上困惑. 多线 ...

  7. CRL快速开发框架系列教程六(分布式缓存解决方案)

    本系列目录 CRL快速开发框架系列教程一(Code First数据表不需再关心) CRL快速开发框架系列教程二(基于Lambda表达式查询) CRL快速开发框架系列教程三(更新数据) CRL快速开发框 ...

  8. C#微信公众号开发系列教程六(被动回复与上传下载多媒体文件)

    微信公众号开发系列教程一(调试环境部署) 微信公众号开发系列教程一(调试环境部署续:vs远程调试) C#微信公众号开发系列教程二(新手接入指南) C#微信公众号开发系列教程三(消息体签名及加解密) C ...

  9. 2015年12月28日 Java基础系列(六)流

    2015年12月28日 Java基础系列(六)流2015年12月28日 Java基础系列(六)流2015年12月28日 Java基础系列(六)流

  10. [转]Android Studio系列教程六--Gradle多渠道打包

    转自:http://www.stormzhang.com/devtools/2015/01/15/android-studio-tutorial6/ Android Studio系列教程六--Grad ...

随机推荐

  1. springboot+kaptcha生成数学运算验证码和字符验证码

    使用以下代码只需要复制粘贴,修改一处文本生成器路径即可,文中有交代. 1.添加kaptcha依赖 <dependency> <groupId>com.github.penggl ...

  2. spring boot2集成api文档工具swagger-ui(上)

    说明 第一步:创建项目 浏览器打开:https://start.spring.io/,生成一个spring boot项目 点击Generate这个按钮,下载项目包文件 第二步:导入开发工具 打开下载目 ...

  3. 虚幻引擎UE4如何实现打包后播放片头?其实超简单!

    虚幻引擎作为一款全球性的3D实时开发工具,不仅在游戏行业,其在建筑.影视.医疗等行业也被广泛使用.作为开发人员,有时开发的UE虚幻引擎项目比较大,开始运行项目时需要等待较长的时间,还有些公司要求添加片 ...

  4. Python 查找PDF中的指定文本并高亮显示

    在处理大量PDF文档时,有时我们需要快速找到特定的文本信息.本文将提供以下三个Python示例来帮助你在PDF文件中快速查找并高亮指定的文本. 查找并高亮PDF中所有的指定文本 查找并高亮PDF某个区 ...

  5. 记录--get请求参数放在body中?

    这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 1.背景 与后端对接口时,看到有一个get请求的接口,它的参数是放在body中的 ******get请求参数可以放在body中?? 随即问 ...

  6. 记录--微信调用jssdk--Invalid Signature, updateAppMessageShareData: denied等问题

    这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 最近在做安卓内嵌入H5活动页拉新活动,遇到的棘手问题记录下, 一是为了日后遇到同样问题好回顾,二是希望能帮到有同样问题的兄弟. 废话不多说 ...

  7. C++ Concurrency in Action 读书笔记一:thread的管理

    为避免混淆,用thread表示std::thread及其对象实例,用线程表示操作系统概念下的线程 Chapter 2 thread的管理 2.1 thread的创建(构造函数) a. 默认构造函数 d ...

  8. KingbaseESV8R6使用pageinspect插件观察空值

    前言 在KingbaseES元组头数据中,有一个t_bits数组,用于存储空值位图.当元组中没有null值的时候,t_bits是空的,当元组有null值的列时,t_bits使用一个bit来表示列是否为 ...

  9. 浅谈 KingbaseES 和 SQLServer 中的 instead of 触发器

    本文基于Kingbase和SqlServer的INSTEAD OF 触发器主要功能特点进行对比浅析,同时针对SqlServer 的INSTEAD OF 触发器提出了多种kingbase环境的等价代码方 ...

  10. #轮廓线dp#HDU 1400 Mondriaan's Dream

    题目传送门 分析 状压dp会TLE,考虑用轮廓线dp, 设 \(dp[i][j][S]\) 表示现在处理到 \((i,j)\) 这个位置轮廓线上状态为 \(S\) 的情况 二进制位为1表示左边或者上方 ...