在现代 Web 应用程序开发中,C# 并发编程成为了一个关键的技能。而在精神和时间上如此成本高昂的开发过程中,优化成为了你必须具备的养成性能的一部分。本文将介绍 C# 并发编程下的性能优化技巧,这些技巧将使您的代码更快,更可扩展,更健壮。
1. 多线程编程时的竞争条件
在多线程下运行代码时,一个常见的问题是竞态条件。当多个线程在读/写共享资源时,如果它们不被正确同步,就会导致数据无效或不一致。但是,防止各种竞争条件可以导致低效代码。
例如,考虑使用 lock 语句来避免竞争条件。 Lock 可以确保在同一时间只有一个线程可以进入指定的代码块,这可以避免一些竞争条件。但是,如果使用不当,lock 可能会阻塞其他线程并导致性能下降。以下是使用 lock 语句的示例代码:
-- -------------------- ---- -------
----- -------
-
------- ------ --- ------- - --
------ -------- ------ ------- - --- ---------
------ ---- ------------- -----
-
--- ------- - --- ---------------
------- - - -- - - -- ----
-
--- ------ - --- --------- --
-
------- - - -- - - -------- ----
-
-------------------
-
---
--------------------
-
----------------- -- -----------
----------------- -- ----------
-------------------------- - - - ---------
-------------------
-
------ ---- ------------------
-
---- ---------
-
----------
-
-
-上述代码使用一个静态的 object 变量来在所有线程之间共享锁定。虽然这段代码可以避免竞争条件,但是当所有线程都运行时,程序进入一种阻塞状态,因为线程互相阻塞以等待释放锁。
要解决这个问题,并在代码中更好地利用多线程处理能力,我们可以将计数器分割为多个块,每个块都有其自己的锁定对象。以下是示例代码:
-- -------------------- ---- -------
----- -------
-
------- ------ ----- ------------- - --- ---------
------ -------- -------- -------- - ------------------- ------------- -- --- --------------------
------ ---- ------------- -----
-
--- ------- - --- ---------------
------- - - -- - - -- ----
-
--- ------ - --- --------- --
-
------- - - -- - - -------- ----
-
--- ----- - ------------
-----------------------------
-
---
--------------------
-
----------------- -- -----------
----------------- -- ----------
--- ------- - --------------------
-------------------------- - - - ---------
-------------------
-
------ --- ------------ ------
-
------ ----- - ----
-
------ ---- ------------------------- ------
-
---- -----------------
-
-----------------------
-
-
-2. 并发集合类的使用
对于并发编程,System.Collections.Concurrent 命名空间中有一些集合类可用,这些类是线程安全的。这些类包括 ConcurrentDictonary、ConcurrentQueue、ConcurrentStack 和 ConcurrentBag。使用这些类可避免手动同步代码,并且它们适用于高效的写操作。
例如,以下示例代码用于计算字符串数组中每个单词出现的次数。使用公共的线程安全 ConcurrentDictionary 类型保存单词计数。
-- -------------------- ---- -------
----- -------
-
------ ---- ------------- -----
-
--- --------- - -----
-
----- -- --- ----- ----------
----- -- --- ------ ----------
----- -- --- ---- ---------
--
--- ---------- - --- ---------------------------- -------
--------------------------- -------- --
-
--- ----- - -------------------- - - - -- ---------------------------------------
------- ---- ---- -- ------
-
---------------------------- -- ----- --------- -- -------- - ---
-
---
-------------------------------- -- -------------
-------------------
-
-3. 线程的使用
对于大多数情况下,使用 Task 类型来表示异步操作,可以方便地有效地使用不同的并行操作。例如,以下示例代码使用 Task.WhenAll 并行执行两个操作(下载并解析两个 XML 文件):
-- -------------------- ---- -------
----- -------
-
------ ----- ---- ------------- -----
-
--- ---- - -----
-
----------------------------------------
---------------------------------------
--
--- ----- - --------------- -- ------------------------ -- -------------------------------------
----- --------------------
-
------ ---- -------------------------- ----
-
----- ---- ------ - --- ------------
-
---------------------------
-- ---
-
-
-4. 惰性初始化
在使用并发编程时,可能会遇到需要延迟初始化的场景。对于惰性初始化应采用哪种方法,这取决于情况。以下标准方法描述了哪种惰性初始化方法更适合特定情况:
- 对于线程安全集合的惰性生成,请使用
Lazy<T>类型。例如:
-- -------------------- ---- -------
----- -------
----- ------------------------------
----- -------
-
------ --------------------------------- ----- ---- -
--- --------------------------------- --------
------ ---- ------------- -----
-
------------------------- ---
--------------------------------------
-
-- 对于非集合类型的懒惰初始化,请使用
Interlocked.CompareExchange。例如:
-- -------------------- ---- -------
----- -------
-
------- ------ --- ------
------- ------ --- ----------- - --
------ ---- ------------- -----
-
-------------
-------------------------
-------------------
-
------ ---- ------------
-
-- ------------------------- ------------ -- -- --
-
----- - ---
-
-
-自从进行 C# 并发编程并不容易,我们需要不断学习和尝试。本文介绍了在 C# 并发编程下性能优化的一些技巧,希望本文的介绍对读者在后续的项目中提供有帮助的指导意义。
Source: FunTeaLearn,Please indicate the source for reprints https://funteas.com/post/67813af1935627c900b66fa3