浅谈.NET下的多线程和并行计算(十三)CLR via C#第三版阅读笔记(2)

简介: 线程同步的问题 1) 我们必须找到代码中所有可能被多个线程同时访问的资源,然后使用线程同步来保护资源,并且我们没有办法来验证是不是正确进行了线程同步,包括是否有遗漏和是否对不需要同步的资源进行同步。 2) 线程同步是有损性能的,如果某个操作大量执行,并且这个操作原先的执行时间非常短,那么如果我们对这段操作前后进行锁的申请和释放的话性能可能下降一个数量级。

线程同步的问题

1) 我们必须找到代码中所有可能被多个线程同时访问的资源,然后使用线程同步来保护资源,并且我们没有办法来验证是不是正确进行了线程同步,包括是否有遗漏和是否对不需要同步的资源进行同步。

2) 线程同步是有损性能的,如果某个操作大量执行,并且这个操作原先的执行时间非常短,那么如果我们对这段操作前后进行锁的申请和释放的话性能可能下降一个数量级。

3) 线程同步可能导致更频繁的线程创建和上下文的切换。

当然,只有在下面的情况下才需要线程同步,换句话说我们尽量不要使用下面的方案来导致线程同步:

1) 只有写操作, 如果只是访问只读对象,即使多个线程同时访问也不会改变资源,因此不需要同步,当然如果有写操作的话,即使是读操作也要考虑是不是需要同步。

2) 引用类型或者是可变的类型,如果访问的都是值类型(这里不说比如寄存器缓存的特殊情况)或者说类型是不可变的(比如string),那么我们对类型的获取和改写都是基于新的类型而不是多个线程的共享资源,因此不需要同步。

3) static静态资源,这也就是资源访问域的问题,如果这个资源并不会被多个线程访问到,也就是这个资源属于每个线程本身的,那么当然不需要同步。

最后,微软确保FCL所有静态方法线程安全,但由于性能问题FCL不保证所有实例方法线程安全,我们需要自己实现线程同步。对于我们自己的类库最好也遵从这个标准。

 

两种同步结构

1) 用户模式,硬件提供支持,速度非常快,但是在block的时候消耗CPU资源,在未争用的时候不损失性能

2) 内核模式,操作系统提供支持,速度比较慢,但是很灵活(比如可以设定超时时间,可以等待一组同步结构都可用的时候继续)并且和用户模式想法的是在block的时候可以不消耗CPU

作者进行了一个性能测试:

class Program
{
    static void Main(string[] args)
    {
        Int32 x = 0;
        const Int32 iterations = 5000000;
        Stopwatch sw = Stopwatch.StartNew();

        SimpleSpinLock ssl = new SimpleSpinLock();
        for (Int32 i = 0; i < iterations; i++)
        {
            ssl.Enter(); x++; ssl.Leave();
        }
        Console.WriteLine("Incrementing x in SimpleSpinLock: {0:N0}", sw.ElapsedMilliseconds);
        using (SimpleWaitLock swl = new SimpleWaitLock())
        {
            sw = Stopwatch.StartNew();
            for (Int32 i = 0; i < iterations; i++)
            {
                swl.Enter(); x++; swl.Leave();
            }
            Console.WriteLine("Incrementing x in SimpleWaitLock: {0:N0}", sw.ElapsedMilliseconds);
        }
    }
}

struct SimpleSpinLock
{
    private Int32 m_ResourceInUse;
    public void Enter()
    {
        while (Interlocked.Exchange(ref m_ResourceInUse, 1) != 0)
        {
        }
    }
    public void Leave()
    {
        Thread.VolatileWrite(ref m_ResourceInUse, 0);
    }
}

class SimpleWaitLock : IDisposable
{
    private AutoResetEvent m_ResourceFree = new AutoResetEvent(true);
    public void Enter()
    {
        m_ResourceFree.WaitOne();
    }
    public void Leave()
    {
        m_ResourceFree.Set();
    }
    public void Dispose() 
    {
        m_ResourceFree.Close();
    }
}

结果表明基于内核模式的同步比基于用户模式的同步慢了数十倍:

image

有关内核模式的各种结构我们在之前的文章中介绍了很多,在这里再补充一下两种用户模式的同步结构:

1) Volatile

两个作用一是防止编译器JIT甚至CPU对代码和指令等进行优化(比如跳过判断,调整代码次序),二是防止多核CPU分别在自己的寄存器中缓存了值导致的不一致性,让值始终从内存中读取。

2) Interlocked

Interlocked.Exchange和Interlocked.CompareExchange分别用于确保赋值操作和比较赋值操作的原子性,值得一提的是,Interlocked.Exchange并没有提供bool重载,我们可以使用int的0和1替代。还有,Interlocked.Read只提供了long重载,那是因为读一个long值的任何操作在32位操作系统上不是原子行为,而在64位操作系统上long的读操作是原子的。

作者: lovecindywang
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
相关文章
|
3月前
|
开发框架 Java .NET
.net core 非阻塞的异步编程 及 线程调度过程
【11月更文挑战第12天】本文介绍了.NET Core中的非阻塞异步编程,包括其基本概念、实现方式及应用示例。通过`async`和`await`关键字,程序可在等待I/O操作时保持线程不被阻塞,提高性能。文章还详细说明了异步方法的基础示例、线程调度过程、延续任务机制、同步上下文的作用以及如何使用`Task.WhenAll`和`Task.WhenAny`处理多个异步任务的并发执行。
|
4月前
|
SQL 传感器 开发框架
今天我们聊聊C#的并发和并行
今天我们聊聊C#的并发和并行
101 1
|
5月前
|
SQL 开发框架 安全
并发集合与任务并行库:C#中的高效编程实践
在现代软件开发中,多核处理器普及使多线程编程成为提升性能的关键。然而,传统同步模型在高并发下易引发死锁等问题。为此,.NET Framework引入了任务并行库(TPL)和并发集合,简化并发编程并增强代码可维护性。并发集合允许多线程安全访问,如`ConcurrentQueue&lt;T&gt;`和`ConcurrentDictionary&lt;TKey, TValue&gt;`,有效避免数据不一致。TPL则通过`Task`类实现异步操作,提高开发效率。正确使用这些工具可显著提升程序性能,但也需注意任务取消和异常处理等常见问题。
75 1
|
6月前
|
开发框架 监控 .NET
|
8月前
|
开发框架 监控 Java
【.NET Core】多线程之线程池(ThreadPool)详解(二)
【.NET Core】多线程之线程池(ThreadPool)详解(二)
123 3
|
8月前
|
SQL 开发框架 Java
【.NET Core】多线程之线程池(ThreadPool)详解(一)
【.NET Core】多线程之线程池(ThreadPool)详解(一)
505 2
|
8月前
|
算法 安全 Java
【.NET Core】 多线程之(Thread)详解
【.NET Core】 多线程之(Thread)详解
100 1
|
3月前
|
C# 开发者
C# 一分钟浅谈:Code Contracts 与契约编程
【10月更文挑战第26天】本文介绍了 C# 中的 Code Contracts,这是一个强大的工具,用于通过契约编程增强代码的健壮性和可维护性。文章从基本概念入手,详细讲解了前置条件、后置条件和对象不变量的使用方法,并通过具体代码示例进行了说明。同时,文章还探讨了常见的问题和易错点,如忘记启用静态检查、过度依赖契约和性能影响,并提供了相应的解决建议。希望读者能通过本文更好地理解和应用 Code Contracts。
60 3
|
2月前
|
存储 安全 编译器
学懂C#编程:属性(Property)的概念定义及使用详解
通过深入理解和使用C#的属性,可以编写更清晰、简洁和高效的代码,为开发高质量的应用程序奠定基础。
116 12
|
3月前
|
设计模式 C# 图形学
Unity 游戏引擎 C# 编程:一分钟浅谈
本文介绍了在 Unity 游戏开发中使用 C# 的基础知识和常见问题。从 `MonoBehavior` 类的基础用法,到变量和属性的管理,再到空引用异常、资源管理和性能优化等常见问题的解决方法。文章还探讨了单例模式、事件系统和数据持久化等高级话题,旨在帮助开发者避免常见错误,提升游戏开发效率。
114 4

热门文章

最新文章