首页 > 编程语言 >C#中常见的锁以及用法--18

C#中常见的锁以及用法--18

时间:2025-01-17 15:30:38浏览次数:3  
标签:Task Console 示例 C# 18 -- tasks 线程 WriteLine

目录

一.C#中存在的锁

二.锁的作用

三.锁的概念和定义

关于锁的完整代码示例

代码逐层剖析:

全局变量与同步变量

Lock(锁)关键字示例

Monitor(监视器锁)示例

Mutex(互斥量)示例(支持跨进程同步)

SemaphoreSlim(信号量)示例

ReadWriterLockSlim(读写锁)示例

SpinLock(自旋锁)示例

InterLocked示例

任务并行库(TPL)同步示例

总结


在C#语言中,为了在多线程环境中保护共享资源,防止线程间资源竞争,引入了多种锁的机制

本文将介绍一些常见的C#的锁以及其作用,概念和使用方式

一.C#中存在的锁

  1. lock关键字(基于Monitor):这是C#中最简单和常用的同步机制,用于确保在给定的对象上,同一时间只有一个线程可以进入被锁定的代码块
  2. Monitor类:提供了静态方法Enter和Exit,与lock关键字功能类似,但提供了更细粒度的控制,例如尝试进入和等待通知等
  3. Mutex(互斥量):系统级别的同步机制,可在跨进程之间同步进程,对比lock和Monitor,Mutex可以用于同步不同进程中的线程
  4. Semaphore和SemaphoreSlim:信号量允许限定一定数量的线程同时访问一个资源,SemaphoreSlim是轻量级版本,主要用于进程内同步
  5. ReaderWriterLockSlim:允许多个线程同时读取资源,但在写入时,要求独占访问.适用于读多写少的场景,以提高并发性能
  6. SpinLock:一种自旋锁,用于短时间的锁定,可以减少线程上下文切换的开销,但是需要去谨慎的去使用,避免占用CPU时间过长
  7. Interlocked类:提供了一组原子操作,能够在不使用锁的情况下对共享变量进行线程安全的操作,例如增减,交换,比较交换等
  8. Task并行库中的常用机制:如CannellationToken,Barrier,CountdownEvent等,用于更高层次的任务同步

二.锁的作用

  1. 线程同步: 确保多个线程在访问共享资源时,不会产生数据不一致或者是竞态条件
  2. 保证数据的完整性:通过控制对资源的并发访问,防止数据损坏或者出现不可预期的结果
  3. 管理线程执行顺序:在复杂的多线程应用中,控制线程的执行顺序,确保程序按照预期的逻辑运行

三.锁的概念和定义

  • 锁(Lock):是一种同步机制,用于确保在同一时间,只有一个线程可以访问某一资源或者执行某段代码,锁可以防止多个线程共同修改共享数据,导致数据不一致.
  • 互斥(Mutual Exclusion):指在多线程环境中,确保只有一个线程能够访问共享资源的特性.
  • 临界区(Critical Section):程序中访问共享资源的代码块,需要被保护以防止并发访问.
  • 死锁(Deadlock):当多个线程互相等待对方释放资源时,导致程序无法继续执行的状态.

关于锁的完整代码示例


    // 共享资源
    private static int _sharedResource = 0;
    private static List<int> _sharedList = new List<int>();
    
    // 各种锁的对象声明
    private static readonly object _lockObject = new object();
    private static readonly object _monitorLock = new object();
    private static readonly Mutex _mutex = new Mutex();
    private static readonly SemaphoreSlim _semaphore = new SemaphoreSlim(2); // 允许2个并发访问
    private static readonly ReaderWriterLockSlim _rwLock = new ReaderWriterLockSlim();
    private static SpinLock _spinLock = new SpinLock();
    
    static async Task Main(string[] args)
    {
        // 1. Lock示例
        await DemonstrateLock();
        
        // 2. Monitor示例
        await DemonstrateMonitor();
        
        // 3. Mutex示例
        await DemonstrateMutex();
        
        // 4. Semaphore示例
        await DemonstrateSemaphore();
        
        // 5. ReaderWriterLock示例
        await DemonstrateReaderWriterLock();
        
        // 6. SpinLock示例
        await DemonstrateSpinLock();
        
        // 7. Interlocked示例
        DemonstrateInterlocked();
        
        // 8. 任务并行库同步示例
        await DemonstrateTPLSync();
    }

    // 1. Lock关键字示例
    private static async Task DemonstrateLock()
    {
        Console.WriteLine("\n=== Lock示例 ===");
        var tasks = new List<Task>();
        
        for (int i = 0; i < 3; i++)
        {
            tasks.Add(Task.Run(() =>
            {
                // lock块确保同一时间只有一个线程可以执行这段代码
                lock (_lockObject)
                {
                    _sharedResource++;
                    Console.WriteLine($"Lock: 线程 {Task.CurrentId} 修改资源值为: {_sharedResource}");
                    Thread.Sleep(100); // 模拟工作
                }
            }));
        }
        await Task.WhenAll(tasks);
    }

    // Monitor类示例
    private static async Task DemonstrateMonitor()
    {
        Console.WriteLine("\n=== Monitor示例 ===");
        var tasks = new List<Task>();

        for (int i = 0; i < 3; i++)
        {
            tasks.Add(Task.Run(() =>
            {
                bool lockTaken = false;
                try
                {
                    // 尝试获取锁,设置1秒超时
                    Monitor.TryEnter(_monitorLock, TimeSpan.FromSeconds(1), ref lockTaken);
                    if (lockTaken)
                    {
                        _sharedResource++;
                        Console.WriteLine($"Monitor: 线程 {Task.CurrentId} 修改资源值为: {_sharedResource}");
                        Thread.Sleep(100);
                    }
                    else
                    {
                        Console.WriteLine($"Monitor: 线程 {Task.CurrentId} 未能获取锁");
                    }
                }
                finally
                {
                    // 如果成功获取了锁,则释放
                    if (lockTaken)
                    {
                        Monitor.Exit(_monitorLock);
                    }
                }
            }));
        }
        await Task.WhenAll(tasks);
    }

    // 3. Mutex示例(支持跨进程同步)
    private static async Task DemonstrateMutex()
    {
        Console.WriteLine("\n=== Mutex示例 ===");
        var tasks = new List<Task>();
        
        // 创建一个命名互斥锁,可以跨进程使用
        using (var namedMutex = new Mutex(false, "GlobalMutexExample"))
        {
            for (int i = 0; i < 3; i++)
            {
                tasks.Add(Task.Run(() =>
                {
                    try
                    {
                        namedMutex.WaitOne();
                        _sharedResource++;
                        Console.WriteLine($"Mutex: 线程 {Task.CurrentId} 修改资源值为: {_sharedResource}");
                        Thread.Sleep(100);
                    }
                    finally
                    {
                        namedMutex.ReleaseMutex();
                    }
                }));
            }
            await Task.WhenAll(tasks);
        }
    }

    // 4. SemaphoreSlim示例
    private static async Task DemonstrateSemaphore()
    {
        Console.WriteLine("\n=== SemaphoreSlim示例 ===");
        var tasks = new List<Task>();
        
        // 创建4个任务,但同时只允许2个任务执行
        for (int i = 0; i < 4; i++)
        {
            tasks.Add(Task.Run(async () =>
            {
                await _semaphore.WaitAsync();
                try
                {
                    Console.WriteLine($"Semaphore: 线程 {Task.CurrentId} 开始执行");
                    await Task.Delay(500);
                }
                finally
                {
                    _semaphore.Release();
                    Console.WriteLine($"Semaphore: 线程 {Task.CurrentId} 释放信号量");
                }
            }));
        }
        await Task.WhenAll(tasks);
    }

    // 5. ReaderWriterLockSlim示例
    private static async Task DemonstrateReaderWriterLock()
    {
        Console.WriteLine("\n=== ReaderWriterLockSlim示例 ===");
        var tasks = new List<Task>();
        
        // 添加多个读取任务
        for (int i = 0; i < 3; i++)
        {
            tasks.Add(Task.Run(() =>
            {
                _rwLock.EnterReadLock();
                try
                {
                    Console.WriteLine($"Reader: 线程 {Task.CurrentId} 正在读取");
                    Thread.Sleep(100);
                }
                finally
                {
                    _rwLock.ExitReadLock();
                }
            }));
        }

        // 添加写入任务
        tasks.Add(Task.Run(() =>
        {
            _rwLock.EnterWriteLock();
            try
            {
                Console.WriteLine($"Writer: 线程 {Task.CurrentId} 正在写入");
                Thread.Sleep(200);
            }
            finally
            {
                _rwLock.ExitWriteLock();
            }
        }));

        await Task.WhenAll(tasks);
    }

    // 6. SpinLock示例
    private static async Task DemonstrateSpinLock()
    {
        Console.WriteLine("\n=== SpinLock示例 ===");
        var tasks = new List<Task>();
        
        for (int i = 0; i < 3; i++)
        {
            tasks.Add(Task.Run(() =>
            {
                bool lockTaken = false;
                try
                {
                    _spinLock.Enter(ref lockTaken);
                    _sharedResource++;
                    Console.WriteLine($"SpinLock: 线程 {Task.CurrentId} 修改资源值为: {_sharedResource}");
                    // SpinLock适用于非常短的操作,这里仅作演示
                }
                finally
                {
                    if (lockTaken) _spinLock.Exit();
                }
            }));
        }
        await Task.WhenAll(tasks);
    }

    // 7. Interlocked示例
    private static void DemonstrateInterlocked()
    {
        Console.WriteLine("\n=== Interlocked示例 ===");
        
        // 原子递增操作
        int value = Interlocked.Increment(ref _sharedResource);
        Console.WriteLine($"Interlocked递增后的值: {value}");

        // 原子交换操作
        int original = Interlocked.Exchange(ref _sharedResource, 100);
        Console.WriteLine($"交换前的值: {original}, 交换后的值: {_sharedResource}");

        // 比较并交换操作
        int comparand = 100;
        int newValue = 200;
        int result = Interlocked.CompareExchange(ref _sharedResource, newValue, comparand);
        Console.WriteLine($"比较交换结果: {result}, 当前值: {_sharedResource}");
    }

    // 8. 任务并行库同步示例
    private static async Task DemonstrateTPLSync()
    {
        Console.WriteLine("\n=== TPL同步示例 ===");
        
        // 使用CancellationTokenSource来控制任务取消
        using (var cts = new CancellationTokenSource())
        {
            // 创建一个Barrier,等待3个任务都完成某个阶段
            var barrier = new Barrier(3);
            var tasks = new List<Task>();

            for (int i = 0; i < 3; i++)
            {
                tasks.Add(Task.Run(() =>
                {
                    Console.WriteLine($"任务 {Task.CurrentId} 开始第一阶段");
                    barrier.SignalAndWait(); // 等待所有任务完成第一阶段

                    Console.WriteLine($"任务 {Task.CurrentId} 开始第二阶段");
                    barrier.SignalAndWait(); // 等待所有任务完成第二阶段

                }, cts.Token));
            }

            await Task.WhenAll(tasks);
        }
Console.ReadKey();
    }

代码逐层剖析:

全局变量与同步变量

// 共享资源   
private static int _sharedResource = 0;   
private static List<int> _sharedList = new List<int>();
   
// 各种锁的对象声明   
private static readonly object _lockObject = new object();   
private static readonly object _monitorLock = new object();   
private static readonly Mutex _mutex = new Mutex();   
private static readonly SemaphoreSlim _semaphore = new SemaphoreSlim(2); // 允许2个并发访问   
private static readonly ReaderWriterLockSlim _rwLock = new ReaderWriterLockSlim();   
private static SpinLock _spinLock = new SpinLock();

_sharedResource:这是一个整数,作为共享的资源,多个线程会对其进行读写

_sharedList:一个整数列表,用于示例需要

_lockObject等同步对象:这些对象用于各自的同步原语,以确保线程安全

Lock(锁)关键字示例


 private static async Task DemonstrateLock()
 {
     Console.WriteLine("\n=== Lock示例 ===");
     var tasks = new List<Task>();
     
     for (int i = 0; i < 3; i++)
     {
         tasks.Add(Task.Run(() =>
         {
             // lock块确保同一时间只有一个线程可以执行这段代码
             lock (_lockObject)
             {
                 _sharedResource++;
                 Console.WriteLine($"Lock: 线程 {Task.CurrentId} 修改资源值为: {_sharedResource}");
                 Thread.Sleep(100); // 模拟工作
                 Console.WriteLine($"Lock: 线程 {Task.CurrentId} 释放锁");
             }
         }));
     }
     await Task.WhenAll(tasks);
 }

代码解释:

  • 目的:演示了lock关键字的使用,即如何确保在一个代码块内同时只能有一个线程运行
  • 实现细节:
    • 创建了三个任务,每个任务都尝试访问共享资源 _sharedResource
    • 使用lock(_lockObject)来锁定代码块,这样同一时间只有一个线程能够进入该代码块
    • 在锁定的代码块内,递增_sharedResource的值并输出当前线程的信息
  • 重要性:lock是C#中最基本的同步机制,使用简单,但只能用于同一进程内的线程同步

代码运行结果展示

Monitor(监视器锁)示例

private static async Task DemonstrateMonitor()   
{
    Console.WriteLine("\n=== Monitor示例 ===");
    var tasks = new List<Task>();

    for (int i = 0; i < 3; i++)
    {
        tasks.Add(Task.Run(() =>
        {
            bool lockTaken = false;
            try
            {
                // 尝试获取锁,设置1秒超时
                Monitor.TryEnter(_monitorLock, TimeSpan.FromSeconds(1), ref lockTaken);
                if (lockTaken)
                {
                    _sharedResource++;
                    Console.WriteLine($"Monitor: 线程 {Task.CurrentId} 修改资源值为: {_sharedResource}");
                    Thread.Sleep(100);
                }
                else
                {
                    Console.WriteLine($"Monitor: 线程 {Task.CurrentId} 未能获取锁");
                }
            }
            finally
            {
                // 如果成功获取了锁,则释放
                if (lockTaken)
                {
                    Console.WriteLine($"Monitor: 线程 {Task.CurrentId} 释放锁");
                    Monitor.Exit(_monitorLock);
                }
            }
        }));
    }
    await Task.WhenAll(tasks);
}

代码解释:

  • 目的:演示Monitor类的使用,特别是TryEnter方法,以及如何手动管理锁的获取和释放
  • 实现细节:
    • 创建了三个任务,每个任务尝试获取_monitorLock的锁
    • 使用Monitor.TryEnter方法,设置了一秒的超时时间,如果在这段时间内未能获取到锁,则返回False
    • lockTaken是一个布尔量,表示是否成功获取到锁
    • 如果成功获取了锁,执行共享资源的操作;否则输出未能获取锁的信息
    • 在Finally块中,检查是否获取了锁,如果是,则调用Monitor.Exit释放锁
  • 重要性:Monitor类提供了比lock更灵活的机制,比如超时等待,尝试获取锁等

代码运行结果展示:

Mutex(互斥量)示例(支持跨进程同步)

private static async Task DemonstrateMutex()
{
    Console.WriteLine("\n=== Mutex示例 ===");
    var tasks = new List<Task>();
    
    // 创建一个命名互斥锁,可以跨进程使用
    using (var namedMutex = new Mutex(false, "GlobalMutexExample"))
    {
        for (int i = 0; i < 3; i++)
        {
            tasks.Add(Task.Run(() =>
            {
                try
                {
                    namedMutex.WaitOne();
                    _sharedResource++;
                    Console.WriteLine($"Mutex: 线程 {Task.CurrentId} 修改资源值为: {_sharedResource}");
                    Thread.Sleep(100);
                }
                finally
                {
                    Console.WriteLine($"Mutex: 线程 {Task.CurrentId} 释放锁");
                    namedMutex.ReleaseMutex();
                }
            }));
        }
        await Task.WhenAll(tasks);
    }
}

代码解释:

  • 目的:演示Mutex(互斥量)的使用,特别是命名互斥量的跨进程同步特性
  • 实现细节:
    • 使用 new Mutex(false,"GlobalMutexExample")创建了一个命名的全局互斥锁,可以在不同的进程间共享
    • 创建了3个任务,每个任务尝试进入互斥锁的临界区
    • 使用 namedMutex.WaitOne()等待获取互斥锁
    • 获取锁后,修改共享资源并输出信息
    • 在finally块中,调用namedMutex.ReleaseMutex()释放互斥锁
  • 重要性:Mutex可以用于跨进程的同步,这在需要多个进程访问同一资源时十分有用

代码运行结果展示:

SemaphoreSlim(信号量)示例

private static async Task DemonstrateSemaphore()   
{
    Console.WriteLine("\n=== SemaphoreSlim示例 ===");
    var tasks = new List<Task>();
    
    // 创建4个任务,但同时只允许2个任务执行
    for (int i = 0; i < 4; i++)
    {
        tasks.Add(Task.Run(async () =>
        {
            await _semaphore.WaitAsync();
            try
            {
                Console.WriteLine($"Semaphore: 线程 {Task.CurrentId} 开始执行");
                await Task.Delay(500);
            }
            finally
            {
                _semaphore.Release();
                Console.WriteLine($"Semaphore: 线程 {Task.CurrentId} 释放信号量");
            }
        }));
    }
    await Task.WhenAll(tasks);
}

代码解释:

  • 目的:演示SemaphoreSlim的使用,控制同时访问某资源的线程数
  • 实现细节:
    • _semaphore初始化时设置了初始计数值为2,因此最多允许2个线程同时进入
    • 创建了四个任务,每个任务都试图获取信号量
    • 使用await _semaphore.WaitAsync() 异步地等待信号量
    • 获取信号量后,输出信息并等待500毫秒,模拟工作
    • 在finally块中,调用 _semaphore.Release() 方法去释放信号量,并输出信息
  • 重要性:信号量用于限制同时访问某资源或代码块的线程数量,SemaphoreSlim是线程内的轻量级版本

代码运行展示:

ReadWriterLockSlim(读写锁)示例

private static async Task DemonstrateReaderWriterLock()   
{
    Console.WriteLine("\n=== ReaderWriterLockSlim示例 ===");
    var tasks = new List<Task>();
    
    // 添加多个读取任务
    for (int i = 0; i < 3; i++)
    {
        tasks.Add(Task.Run(() =>
        {
            _rwLock.EnterReadLock();
            try
            {
                Console.WriteLine($"Reader: 线程 {Task.CurrentId} 正在读取");
                Thread.Sleep(100);
            }
            finally
            {
                _rwLock.ExitReadLock();
            }
        }));
    }

    // 添加写入任务
    tasks.Add(Task.Run(() =>
    {
        _rwLock.EnterWriteLock();
        try
        {
            Console.WriteLine($"Writer: 线程 {Task.CurrentId} 正在写入");
            Thread.Sleep(200);
        }
        finally
        {
            _rwLock.ExitWriteLock();
        }
    }));

    await Task.WhenAll(tasks);
}

代码解释:

  • 目的:演示ReadWriterLockSlim的使用,允许多个线程同时读取,但写入时需要独占
  • 实现细节:
    • 创建了3个读取任务,使用_rwLock.EnterReadLock()获取读锁
    • 创建了1个写入任务,使用_rwLock.EnterWriteLock()获取写锁
    • 读取任务之间可以并发执行,但写入任务需要等待所有读锁释放后才能获取写锁
    • 每个任务在完成后,调用相应的ExitReadLock()和ExitWriteLock()释放锁
  • 重要性:读写锁提高了并发性能,适用于读多写少的情景

代码运行结果展示:

SpinLock(自旋锁)示例

private static async Task DemonstrateSpinLock()   
{
    Console.WriteLine("\n=== SpinLock示例 ===");
    var tasks = new List<Task>();
    
    for (int i = 0; i < 3; i++)
    {
        tasks.Add(Task.Run(() =>
        {
            bool lockTaken = false;
            try
            {
                _spinLock.Enter(ref lockTaken);
                _sharedResource++;
                Console.WriteLine($"SpinLock: 线程 {Task.CurrentId} 修改资源值为: {_sharedResource}");
                // SpinLock适用于非常短的操作,这里仅作演示
            }
            finally
            {
                if (lockTaken) _spinLock.Exit();
            }
        }));
    }
    await Task.WhenAll(tasks);
}

代码解释:

  • 目的:演示了SpinLock的使用,它是一种自旋锁,适用于非常短时间的锁定操作
  • 实现细节:
    • 创建了三个任务,每个任务都尝试获取_spinLock的锁
    • 使用_spinLock.Enter(ref lockTaken)来获取锁
    • 获取锁后,修改共享资源并输出信息
    • 在finally块中,检查lockTaken,如果获取了锁,则调用_spinLock.Exit()方法释放锁
  • 重要性:SpinLock适用于非常短的临界区,因为它会一直循环等待直至获取锁,避免线程上下文的切换,但如果操作时间过长,会导致CPU占用过高

在使用自旋锁时,一定要去释放锁,否则会造成死锁

代码运行结果展示:

InterLocked示例

private static void DemonstrateInterlocked()   
{
    Console.WriteLine("\n=== Interlocked示例 ===");
    
    // 原子递增操作
    int value = Interlocked.Increment(ref _sharedResource);
    Console.WriteLine($"Interlocked递增后的值: {value}");

    // 原子交换操作
    int original = Interlocked.Exchange(ref _sharedResource, 100);
    Console.WriteLine($"交换前的值: {original}, 交换后的值: {_sharedResource}");

    // 比较并交换操作
    int comparand = 100;
    int newValue = 200;
    int result = Interlocked.CompareExchange(ref _sharedResource, newValue, comparand);
    Console.WriteLine($"比较交换结果: {result}, 当前值: {_sharedResource}");
}

代码解释:

  • 目的:演示InterLocked类的使用,用于执行原子操作,避免显示的锁定
  • 实现细节:
    • Interlocked.Increment:对共享变量执行原子递增操作,返回递增后的值
    • Interlocked.Exchange:将共享变量设置为新值,并返回原始值
    • Interlocked.CompareExchange:如果共享变量的值等于比较值,则将其设置为新值,并返回原始值
  • 重要性:InterLocked提供了高效的线程安全操作,适用于简单的变量操作,而不需要使用锁

代码运行结果展示:

任务并行库(TPL)同步示例

private static async Task DemonstrateTPLSync()   
{
    Console.WriteLine("\n=== TPL同步示例 ===");
    
    // 使用CancellationTokenSource来控制任务取消
    using (var cts = new CancellationTokenSource())
    {
        // 创建一个Barrier,等待3个任务都完成某个阶段
        var barrier = new Barrier(3);
        var tasks = new List<Task>();

        for (int i = 0; i < 3; i++)
        {
            tasks.Add(Task.Run(() =>
            {
                Console.WriteLine($"任务 {Task.CurrentId} 开始第一阶段");
                barrier.SignalAndWait(); // 等待所有任务完成第一阶段

                Console.WriteLine($"任务 {Task.CurrentId} 开始第二阶段");
                barrier.SignalAndWait(); // 等待所有任务完成第二阶段

            }, cts.Token));
        }

        await Task.WhenAll(tasks);
    }
    Console.ReadKey();
}

代码解释:

  • 目的:演示任务并行库(TPL)中的同步机制,特别是Barrier的使用
  • 实现细节:
    • 创建了一个Barrier,参与方数量为3,表示需要等待三个任务
    • 创建了3个任务,每个任务在两个阶段都调用了barrier.SignalAndWait();
      • 第一阶段:任务输出开始第一阶段的信息,然后调用barrier.SignalAndWait(),等待其他任务也完成第一阶段
      • 第二阶段:任务输出开始第二阶段的信息,然后再次调用barrier.SignalAndWait()
    • CancellationTokenSource可以控制任务的取消
  • 重要性:Barrier用于协调多个任务的执行,使得它们可以在某个同步点等待彼此,同步进入下一阶段的操作

代码运行结果展示:


总结

  • lock和Monitor:适用于简单的线程同步,同一进程内的线程
  • Mutex:可用于跨进程的同步,但性能较 lock 较低
  • SemaphoreSlim:控制同时访问资源的线程数量
  • ReadWriterLockSlim:优化读多写少的场景,提高并发性能
  • SpinLock:适用于非常短的锁定操作,避免线程上下文切换,但可能导致CPU占用高
  • InterLocked:提供简单的原子操作,性能高,没有锁开销
  • 任务并行库同步机制""提供高级的同步方式,如 Barrier,CountdownEvent 等

标签:Task,Console,示例,C#,18,--,tasks,线程,WriteLine
From: https://blog.csdn.net/O_____V_____O/article/details/145189816

相关文章

  • CentOS等各类Linux系统安装配置Docker详细教程(全网最详细,步骤简洁,看完包懂)
    文章目录前言详细步骤1.安装相关依赖2.安装阿里云的DockerGPG密钥3.设置stable仓库4.安装Docker5.启动服务6.验证测试常见问题及对应解决方案补充1.Ubuntu等系统配置Docker详细教程CentOS9配置Docker-速通版前言Docker是一个非常常用的工具,但是由于其涉及......
  • Git基本操作
    Git是一个分布式版本控制系统,它可以追踪文件的变化,并记录文件的历史版本。以下是Git的基本概念和使用方式:仓库(Repository):Git仓库是存储代码和文件的地方,可以是本地仓库或远程仓库。本地仓库存储在本地计算机上,而远程仓库存储在远程服务器上。分支(Branch):分支是Git中的重要概......
  • Vue3初学之Element-plus Form表单
    1.使用el-form组件el-form是一个表单容器,可以包含多个el-form-item,每个el-form-item包裹具体的表单控件,如输入框、选择器、日期选择器等。<template><el-form:model="form"label-width="120px"><el-form-itemlabel="用户名"><el-inputv-mod......
  • 规避路由冲突
    路由冲突是指在网络中存在两个或多个路由器在进行路由选择时出现矛盾,导致网络数据包无法正确传输,影响网络的正常运行。为了规避路由冲突,可以采取以下措施:一、合理规划IP地址分配唯一IP:确保每个设备在网络中都有唯一的IP地址。可以通过登录路由器管理界面,查看和分配IP地址,避免......
  • 刀片机还是一体机
    做边缘计算汇聚时,用刀片机好还是用一体机x86比较好呢?今天我们一起来聊一聊两者的优缺点,可以根据自己的需求进行选择。刀片机优点一,扩展性比较强,模块化设计可以根据自己的需求灵活的增加或减少计算资源、存储资源或网络的资源。二、性能强大。每个刀片机都是一个独立的服务器......
  • 安装盒子or搭建机房
    1选择做PCDN时是安装盒子还是搭建机房,取决于您的业务规模、预算、技术需求以及长期战略。以下是针对这两种方案的详细分析和建议,帮助您做出最适合的选择:安装盒子(家庭用户设备或小型服务器)优点初期成本低:购买和安装家用设备或小型服务器的成本相对较低,适合预算有限的情况。......
  • 《AI语言模型的关键技术探析:系统提示、评估方法与提示工程》
    文章主要内容摘要1.系统提示(SystemPrompt)定义:用于设置模型行为、角色和工作方式的特殊指令重要性:定义模型行为边界影响输出质量和一致性可将通用模型定制为特定领域助手挑战:技术集成复杂兼容性问题效果难以精确预测2.模型评估方法创新方向:自一......
  • QObject::moveToThread成员函数
    头文件包含......
  • 实施零信任模型的方法指南 支柱1用户 集成ICAM平台(Integrated ICAM Platform)
    1.9.1功能描述国防部各组织和整个企业采用企业级身份管理和公钥基础设施(PKI)系统,用于跟踪整个网络中的用户、管理员和非人员实体(NPE)的身份,并确保访问权限仅限于有需要且有知情权的人员,各组织可以通过凭证管理系统、身份治理和管理工具以及访问管理工具来验证其是否为必需......
  • 网站目录中的PHP脚本无法写入,导致缓存文件生成失败
    根据您的描述,您遇到了网站目录中的PHP脚本无法写入的问题,这直接影响了缓存文件的生成,进而导致网站运行不正常。具体来说,espcms_datacache/_templates 和 espcms_datacache/dbcache 目录下的PHP文件无法写入,这对网站性能和功能产生了负面影响。要解决这个问题,您可以按照以下步......