当前位置: 首页 > news >正文

做网站一般用什么配置的电脑/域名注册哪个网站好

做网站一般用什么配置的电脑,域名注册哪个网站好,网站开发禁止下载功能,介休门户网站什么是锁? 在程序中,当多个任务(或线程)同时访问同一个资源时,比如多个操作同时修改一份数据,可能会导致数据不一致。这时候,我们需要“锁”来确保同一时间只有一个任务能够操作这个数据&#…

什么是锁?

在程序中,当多个任务(或线程)同时访问同一个资源时,比如多个操作同时修改一份数据,可能会导致数据不一致。这时候,我们需要“锁”来确保同一时间只有一个任务能够操作这个数据,避免“抢占”问题。简单来说,锁就是一种机制,它能帮助你控制多个任务按顺序来操作资源

按照锁的功能来进行分类,iOS常见的锁:自旋、互斥、递归、条件。。。

一、自旋锁

自旋锁的意思就是当资源被占有时,自旋锁不会引起其他调用者休眠,而是让其他调用者自旋,不停的循环访问自旋锁导致调用者处于busy-wait(忙等状态),直到自旋锁的保持者释放锁。自旋锁是为了实现保护共享资源一种锁机制,在任何时刻只能有一个保持者,也就是说在任何时刻只能有一个可执行单元获得锁。也正是因为其他调用者会保持自旋状态,使得在锁的保持者释放锁时能够即刻获得锁,效率非常高。但我们说调用者时刻自旋也是消耗CPU资源的,所以如果自旋锁的使用者保持锁的时间比较短的话,使用自旋锁是非常合适的,因为在锁释放之后省去了唤醒调用者的时间。

1.OSSpinLock(已弃用)

  • OSSpinLock 是一种轻量级的锁。当一个线程获取不到锁时,它不会进入睡眠状态,而是一直循环检查锁是否可用,这叫“自旋”。
  • 缺点OSSpinLock 已经被弃用,因为它容易导致“优先级反转”(低优先级线程获取锁,高优先级线程等待锁释放,造成高优先级线程无法执行)。

2.os_unfair_lock

  • os_unfair_lockOSSpinLock 的替代品。它解决了优先级反转问题,当一个线程无法获取锁时,会立即休眠而不是自旋。

  • 适用场景:用于短时间的锁定操作,轻量、快速。

var unfairLock = os_unfair_lock_s()func safeMethod() {os_unfair_lock_lock(&unfairLock)// 执行共享资源的操作os_unfair_lock_unlock(&unfairLock)
}

用GCD模拟多线程,看是否输出是否按顺序输出:

import Foundation// 初始化不公平锁
var unfairLock = os_unfair_lock_s()// 共享资源(例子:计数器)
var sharedCounter = 0// 线程安全的方法,增量计数器
func safeIncrement() {// 加锁,确保只有一个线程可以访问共享资源os_unfair_lock_lock(&unfairLock)// 临界区:操作共享资源sharedCounter += 1print("计数器增加: \(sharedCounter)") // 输出当前计数器的值// 解锁,允许其他线程访问共享资源os_unfair_lock_unlock(&unfairLock)
}// 使用DispatchQueue模拟多线程
let queue = DispatchQueue.global()// 测试线程安全的方法
for _ in 1...10 {queue.async {safeIncrement() // 多个线程同时操作计数器}
}

输出:

二、互斥锁

互斥锁和自旋锁类似,都是为了解决对某项资源的互斥使用,并且在任意时刻最多只能有一个执行单元获得锁,与自旋锁不同的是,互斥锁在被持有的状态下,其他资源申请者只能进入休眠状态,当锁被释放后,CPU会唤醒资源申请者,然后获得锁并访问资源。

1.pthread_mutex_t

  • pthread_mutex_t 是 POSIX 线程库提供的底层互斥锁,能确保同一时刻只有一个线程访问共享资源。
  • 适用场景:高效多线程编程,适合对性能要求高的场景。
var mutex = pthread_mutex_t()
pthread_mutex_init(&mutex, nil)func safeMethod() {pthread_mutex_lock(&mutex)// 执行共享资源的操作pthread_mutex_unlock(&mutex)
}

同样的GCD模拟多线程,看是否输出是否按顺序输出:

import Foundation
//初始化互斥锁(Mutex)
var mutex = pthread_mutex_t()
pthread_mutex_init(&mutex, nil)// 共享资源(例子:计数器)
var sharedCounter = 0// 线程安全的方法,增量计数器
func safeIncrement() {// 加锁,确保只有一个线程可以访问共享资源pthread_mutex_lock(&mutex)// 临界区,操作共享资源sharedCounter += 1print("计数器增加: \(sharedCounter)") // 输出当前计数器的值// 解锁,允许其他线程访问共享资源pthread_mutex_unlock(&mutex)
}// 使用DispatchQueue模拟多线程
let queue = DispatchQueue.global()// 测试线程安全的方法
for _ in 1...10 {queue.async {safeIncrement() // 多个线程同时操作计数器}
}

输出:

2.NSLock

  • NSLock 是 Cocoa 提供的更高级的互斥锁,它比 pthread_mutex_t 更易于使用。
let lock = NSLock()func safeMethod() {lock.lock()// 执行代码lock.unlock()
}

GCD模拟多线程:

import Foundation
//初始化互斥锁(NSLock)
var lock = NSLock()// 共享资源(例子:计数器)
var sharedCounter = 0// 线程安全的方法,增量计数器
func safeIncrement() {// 加锁,确保只有一个线程可以访问共享资源lock.lock()// 临界区,操作共享资源sharedCounter += 1print("计数器增加: \(sharedCounter)") // 输出当前计数器的值// 解锁,允许其他线程访问共享资源lock.unlock()
}// 使用DispatchQueue模拟多线程
let queue = DispatchQueue.global()// 测试线程安全的方法
for _ in 1...10 {queue.async {safeIncrement() // 多个线程同时操作计数器}
}

3.@synchronized(仅支持 Objective-C)

  • 这是 Objective-C 中提供的自动锁机制,是OC的语法糖,Swift 中无法直接使用。它可以帮助你简化锁定的逻辑。
@synchronized(self) {// 执行共享资源操作
}

三、递归锁

递归锁可以被同一线程多次请求,而不会引起死锁,即在多次被同一个线程进行加锁时,不会造成死锁。这主要是用在循环或递归操作中。

递归锁也是通过 pthread_mutex_lock 函数来实现,在函数内部会判断锁的类型,如果显示是递归锁,就允许递归调用,仅仅将一个计数器加一,等到递归完毕之后,所有锁都会释放

1.NSRecursiveLock

  • NSRecursiveLock 是一种递归锁,允许同一个线程多次获取同一把锁而不会导致死锁。这是 NSLock 无法做到的。
  • 适用于需要多次锁定同一资源的场景。
let recursiveLock = NSRecursiveLock()func recursiveFunction(count: Int) {recursiveLock.lock()if count > 0 {print("Count: \(count)")recursiveFunction(count: count - 1)}recursiveLock.unlock()
}

2.pthread_mutex_t (递归锁)

  • pthread_mutex_t 也可以被设置为递归模式,用法类似 NSRecursiveLock。

四、条件锁

条件是信号量的另一种类型,当某个条件为true时,它允许线程相互发信号。条件通常用于指示资源的可用性或确保任务以特定顺序执行。当线程测试条件时,除非该条件已经为真,否则它将阻塞。它保持阻塞状态,直到其他线程显式更改并发出条件信号为止。条件和互斥锁之间的区别在于,可以允许多个线程同时访问该条件。 

1.pthread_cond_t

  • pthread_cond_t 是一种条件锁,常与 pthread_mutex_t 搭配使用,允许线程在满足特定条件时进行等待或唤醒。
  • 适用场景:用于需要等待某个条件满足的多线程场景。

2.NSCondition

  • NSCondition 是一个高级条件锁,可以让线程根据某些条件来等待或唤醒。
  • NSCondition 的底层是通过条件变量(condition variable) pthread_cond_t 来实现的。条件变量有点像信号量,提供了线程阻塞与信号机制,因此可以用来阻塞某个线程,并等待某个数据就绪,随后唤醒线程,比如常见的生产者-消费者模式。生产者-消费者模式可以查看我的另一篇博客:iOS--生产者-消费者模式理解(附GCD信号量代码实现)-CSDN博客
let condition = NSCondition()
var isReady = falsefunc producer() {condition.lock()isReady = truecondition.signal()  // 唤醒等待中的线程condition.unlock()
}func consumer() {condition.lock()while !isReady {condition.wait()  // 等待条件满足}// 执行消费操作condition.unlock()
}

模拟:

import Foundationlet condition = NSCondition()
var isReady = false// 生产者方法
func producer() {condition.lock()print("生产者正在准备资源...")isReady = trueprint("资源准备完成,通知消费者")condition.signal()  // 唤醒等待的消费者线程condition.unlock()
}// 消费者方法
func consumer() {condition.lock()print("消费者等待资源...")while !isReady {condition.wait()  // 等待条件满足}print("资源已准备好,开始消费资源")// 执行消费操作condition.unlock()
}// 模拟并发:使用DispatchQueue进行生产者和消费者的交互
let queue = DispatchQueue.global()// 消费者等待资源
queue.async {consumer()
}// 模拟生产者延迟生产资源
queue.asyncAfter(deadline: .now() + 2) {producer()
}

3.NSConditionLock

  • NSConditionLock 是 NSCondition 的一种变体,基于条件值进行锁定和解锁,适用于更复杂的线程同步场景。

五、信号量

信号量(Semaphore),有时被称为信号灯,是在多线程环境下使用的一种设施,是可以用来保证两个或多个关键代码段不被并发调用。在进入一个关键代码段之前,线程必须获取一个信号量;一旦该关键代码段完成了,那么该线程必须释放信号量。其它想进入该关键代码段的线程必须等待直到第一个线程释放信号量。为了完成这个过程,需要创建一个信号量VI,然后将Acquire Semaphore VI以及Release Semaphore VI分别放置在每个关键代码段的首末端。确认这些信号量VI引用的是初始创建的信号。

其实本质上,它通过维护一个计数值来控制同时可以访问某一资源的线程数量

1.dispatch_semaphore_t

  • dispatch_semaphore_t 是 GCD 提供的信号量机制,用于控制同时访问某一资源的线程数量。
  • 适用场景:适合控制并发任务的数量。
let semaphore = DispatchSemaphore(value: 1)func safeMethod() {semaphore.wait()   // 请求资源// 执行共享资源操作semaphore.signal() // 释放资源
}

2.pthread_mutex_t(作为信号量使用)

  • 可以通过将 pthread_mutex_tpthread_cond_t 配合使用,达到类似信号量的效果。

六、读写锁

读写锁实际是一种特殊的自旋锁,它把对共享资源的访问者划分成读者和写者,读者只对共享资源进行读访问,写者则需要对共享资源进行写操作。这种锁相对于自旋锁而言,能提高并发性,因为在多处理器系统中,它允许同时有多个读者来访问共享资源,最大可能的读者数为实际的逻辑CPU数。写者是排他性的,一个读写锁同时只能有一个写者或多个读者(与CPU数相关),但不能同时既有读者又有写者。

读写锁适合于对数据结构的读次数比写次数多得多的情况. 因为, 读模式锁定时可以共享, 以写模式锁住时意味着独占, 所以读写锁又叫共享-独占锁。

1.pthread_rwlock_t

  • pthread_rwlock_t 是一种读写锁,它允许多个线程同时读取资源,但在写入时会排他性地锁定。
  • 适用场景:适合读多写少的场景。
var rwlock = pthread_rwlock_t()
pthread_rwlock_init(&rwlock, nil)func readResource() {pthread_rwlock_rdlock(&rwlock)  // 加读锁// 读取资源pthread_rwlock_unlock(&rwlock)  // 解锁
}func writeResource() {pthread_rwlock_wrlock(&rwlock)  // 加写锁// 写入资源pthread_rwlock_unlock(&rwlock)  // 解锁
}

七、栅栏

栅栏函数在GCD中常用来控制线程同步,在队列中它总是等栅栏之前的任务执行完,然后执行栅栏自己的任务,执行完自己的任务后,再继续执行栅栏后的任务。常用函数有同步栅栏函数(dispatch_barrier_sync)和异步栅栏函数(dispatch_barrier_async)。

import Foundation// 创建一个并发队列
let queue = DispatchQueue(label: "com.example.concurrentQueue", attributes: .concurrent)// 异步执行任务1
queue.async {print("Task 1")
}// 异步执行任务2
queue.async {print("Task 2")
}// 使用 barrier 标志的任务,确保在这个任务期间,队列中不会有其他任务执行
queue.async(flags: .barrier) {print("Barrier task")print("Barrier task2")  // 在屏障任务中执行第二个打印
}// 异步执行任务3,等待 barrier 任务执行完毕后继续
queue.async {print("Task 3")
}

输出顺序

• Task 1 和 Task 2 可能无序输出,因为它们是并发执行的。

• 屏障任务会在之前的任务完成后执行。

• Task 3 将在屏障任务结束后执行。

总结:

线程安全

上述学习的各种常见的线程锁,都是为了更好地管理和调配线程,而在开发中我们往往不可避免地采用多线程并发,这虽然很便利但是存在的巨大的安全隐患

什么是线程安全?

线程安全指的是多个线程可能同时操作同一块内存,从而导致的异常情况,先举个例子:

class User {private(set) var name: String = ""func setName(_ name: String) {self.name = name}
}let user = User()let queue1 = DispatchQueue(label: "q1")
let queue2 = DispatchQueue(label: "q2")queue1.async {user.setName("1")print(user.name)
}
queue2.async {user.setName("2")print(user.name)
}

这段代码因为多线程并发同时修改同一个变量,导致可能的结果是测试下来可能会是打印了两个 2,这就不符合我们的预期了,明明第一个 user.setName 传入的是 “1”,打印结果却为 2。

这种情况称为资源竞争,两个线程可能同时操作 user 对象,实际上,除了结果不符合预期外,还可能出现一个经典的崩溃 EXC_BAD_ACCESS,这是因为让两个线程尝试同时操作同一个内存地址导致的。

如何解决资源竞争问题?

很简单,用我们刚学完的锁就可以。这里就不举例子了。。。

其他并发问题

除了上边提到的资源竞争问题,在使用并发的时候还可能导致一些其他问题,也需要注意,比如:

  • 条件竞争:无法同步执行两个或多个线程,导致事件以错误的顺序执行
  • 死锁:两个线程相互等待,这意味着两者都无法继续,线程会卡死
  • 优先级倒置:低优先级任务持有高优先级任务所需的资源,导致执行延迟
  • 线程爆炸:程序中申请的线程数量过多,导致资源耗尽和系统性能下降
  • 线程匮乏:因为其他线程正在占用这个资源,导致其他线程无法访问,从而导致执行延迟

解决方法:

1. 条件竞争
  • 使用锁:使用互斥锁(如NSLock)或信号量(如DispatchSemaphore)确保对共享资源的安全访问。
  • 使用队列:使用串行队列或DispatchQueue的同步方法来控制对共享数据的访问顺序。
2. 死锁
  • 避免嵌套锁:尽量避免一个线程在持有锁时请求另一个锁。
  • 设置锁的顺序:确保所有线程按照相同的顺序获取锁。
  • 使用超时:设置锁的获取超时,防止无限等待。
3. 优先级倒置
  • 优先级提升:在需要时提升低优先级线程的优先级,让所需资源尽快释放。
  • 资源管理:确保高优先级线程能及时访问所需资源,比如使用锁机制。
4. 线程爆炸
  • 限制线程数量:使用线程池管理线程数量,避免创建过多线程。
  • 使用异步任务:采用GCD的队列,减少线程的创建。
5. 线程匮乏
  • 优化资源使用:检查资源访问和锁的使用,确保高效利用资源。
  • 调整线程设计:使用更灵活的线程模型,比如异步编程,减少对共享资源的依赖。

这里重点讲解一下什么是死锁。。。。。

死锁

在 Swift 中,当两个线程都在等待对方释放资源时,就会发生deadlock 死锁。这会导致线程都处于永久等待状态,当主线程死锁,应用的表现上就是崩溃,其他子线程死锁可能导致卡死。

举个例子:

class ViewController: UIViewController {override func viewDidLoad() {super.viewDidLoad()print(1)DispatchQueue.main.sync {print(2)}print(3)}
}

上述代码会输出1后程序崩溃。

原因:主线程是处理用户界面和交互的线程。在viewDidLoad中打印1后,想要在主线程上执行另一个任务(打印2)。使用sync意味着希望这个任务立刻完成,而主线程正在执行viewDidLoad方法。因为主线程正在等着这个新任务完成(打印2),但这个任务又在主线程上运行,所以主线程无法继续,导致死锁

再举一个因为互斥锁而引发死锁的例子:

import Foundation// 创建两个锁
let lock1 = NSLock()
let lock2 = NSLock()// 线程1任务
func thread1() {print("线程1 尝试获取 lock1")lock1.lock()print("线程1 获取了 lock1")// 模拟处理一些操作sleep(1)print("线程1 尝试获取 lock2")lock2.lock()  // 死锁发生在这里,因为线程2已经持有了 lock2print("线程1 获取了 lock2")  // 这行永远不会被执行lock2.unlock()lock1.unlock()
}// 线程2任务
func thread2() {print("线程2 尝试获取 lock2")lock2.lock()print("线程2 获取了 lock2")// 模拟处理一些操作sleep(1)print("线程2 尝试获取 lock1")lock1.lock()  // 死锁发生在这里,因为线程1已经持有了 lock1print("线程2 获取了 lock1")  // 这行永远不会被执行lock1.unlock()lock2.unlock()
}// 并发队列
let queue = DispatchQueue.global()// 启动线程
queue.async {thread1()
}queue.async {thread2()
}
  1.     线程1 首先获取 lock1,然后等待获取 lock2。
  2.     线程2 首先获取 lock2,然后等待获取 lock1。
  3.     由于两个线程互相等待对方释放锁,导致程序进入死锁,两个线程都无法继续执行。

造成死锁的四个条件:

  1. 互斥条件:某个资源一次只能被一个线程占用。
  2. 占有且等待:一个线程占有一个资源,同时等待其他资源。
  3. 不可剥夺:线程所持有的资源不能被强制剥夺。
  4. 循环等待:两个或多个线程形成一种循环等待关系。

解决死锁的策略

  •     避免锁的循环等待:通过统一的锁顺序,确保线程不会互相等待对方的资源
  •     使用超时机制:锁请求可以设置超时时间,防止无限等待
  •     使用NSRecursiveLock(递归锁):允许同一线程多次获取同一把锁,避免递归调用中的死锁问题

参考:

iOS - 线程中常见的几种锁_unlock tryluck-CSDN博客

谈谈 swift 中的线程安全 - 知乎 (zhihu.com)

讲讲 iOS 中的死锁 (qq.com)

相关文章:

近万字深入讲解iOS常见锁及线程安全

什么是锁? 在程序中,当多个任务(或线程)同时访问同一个资源时,比如多个操作同时修改一份数据,可能会导致数据不一致。这时候,我们需要“锁”来确保同一时间只有一个任务能够操作这个数据&#…...

linux创建固定大小的文件夹用于测试

在linux上创建固定大小的文件夹用于测试磁盘空间不足时的应用故障。 实验环境为centos7,有两种简易方法: 一、使用ramdisk 1、创建文件夹 mkdir /var/mytest 2、创建一个1m大小的临时文件 mount none /var/mytest -t tmpfs -o size1m size也可以写…...

大模型学习路线:这会是你见过最全最新的大模型学习路线【2024最新】

大模型学习路线 建议先从主流的Llama开始,然后选用中文的Qwen/Baichuan/ChatGLM,先快速上手体验prompt工程,然后再学习其架构,跑微调脚本 如果要深入学习,建议再按以下步骤,从更基础的GPT和BERT学起&…...

了解云计算工作负载保护的重要性,确保数据和应用程序安全

云计算de小白 云计算技术的快速发展使数据和应用程序安全成为一种关键需求,而不仅仅是一种偏好。随着越来越多的客户公司将业务迁移到云端,保护他们的云工作负载(指所有部署的应用程序和服务)变得越来越重要。云工作负载保护&…...

Swagger3基本使用

Swagger 课程目标 Swagger简介【了解】 Springboot整合swagger【掌握】 Swagger 常用注解【掌握】 knife4j-Swagger【会用】 一、Swagger3简介 Swagger 是一系列 RESTful API 的工具,通过 Swagger 可以获得项目的⼀种交互式文档,客户端 SDK 的自 动…...

如何借助Java批量操作Excel文件?

最新技术资源(建议收藏) https://www.grapecity.com.cn/resources/ 前言 | 问题背景 在操作Excel的场景中,通常会有一些针对Excel的批量操作,批量的意思一般有两种: 对批量的Excel文件进行操作。如导入多个Excel文件…...

JUC并发编程_Lock锁

JUC并发编程_Lock锁 1、Lock锁介绍2、主要方法3、与 synchronized 的区别4、Condition 使用示例 1、Lock锁介绍 Java中的 Lock 锁是 java.util.concurrent.locks 包下的一个接口,它提供了比 synchronized 关键字更灵活的锁定机制。 2、主要方法 lock()&#xff1a…...

Unity中的功能解释(数学位置相关和事件)

向量计算 Vector3.Slerp(起点坐标,终点坐标,t),可是从起点坐标以一个圆形轨迹到终点坐标,有那么多条轨迹,那怎么办 Vector3.Slerp 进行的是沿球面插值,因此并不是沿着严格的“圆形…...

ElementPlus---Timeline 时间线组件使用示例

介绍 使用ElementPlus时间线组件在后台首页实现通知公告列表展示&#xff0c;使用Vue3开发。 实现代码 Vue3代码 <el-timeline><el-timeline-itemstyle"max-width: 600px"v-for"(activity, index) in activities":key"index":times…...

推荐4款2024年大家都在用的高质量翻译器。

翻译器在我们的生活中有着很重要的作用&#xff0c;不管是我们在学习还是工作&#xff0c;生活娱乐&#xff0c;出国旅游等场合都会派上用场&#xff0c;它是我们解决沟通的障碍&#xff0c;提高阅读效率的好帮手。我自己使用的翻译器有很多&#xff0c;可以给大家列举几款特别…...

Mybatis 返回 Map 对象

一、场景介绍 假设有如下一张学生表&#xff1a; CREATE TABLE student (id int NOT NULL AUTO_INCREMENT COMMENT 主键,name varchar(100) NOT NULL COMMENT 姓名,gender varchar(10) NOT NULL COMMENT 性别,grade int NOT NULL COMMENT 年级,PRIMARY KEY (id) ) ENGINEInnoD…...

Vue3(三)路由基本使用、工作模式(history,hash)、query传参和param传参、props配置、编程式路由导航

文章目录 一、路由的基本使用二、路由器的工作模式三、RouterLink中to的两种写法四、嵌套路由五、路由传参1. query传参2. params传参 六、路由的propos配置七、编程式路由导航 一、路由的基本使用 安装&#xff1a;npm i vue-router 在src/pages文件下&#xff0c;创建三个路…...

TypeScript概念讲解

简单来说&#xff0c;TypeScript 是 JavaScript 的一个超集&#xff0c;支持 ECMAScript 6 标准&#xff1b; TypeScript 由微软开发的自由和开源的编程语言&#xff1b; TypeScript 设计目标是开发大型应用&#xff0c;它可以编译成纯 JavaScript&#xff0c;编译出来的 Jav…...

C++ | Leetcode C++题解之第437题路径总和III

题目&#xff1a; 题解&#xff1a; class Solution { public:unordered_map<long long, int> prefix;int dfs(TreeNode *root, long long curr, int targetSum) {if (!root) {return 0;}int ret 0;curr root->val;if (prefix.count(curr - targetSum)) {ret pref…...

回复《对话损友 2》

回复《对话损友 2》 承蒙贵人挂念&#xff0c;亦感激贵人给予这般交流的契机&#xff08;对话损友 2 -- 回复-CSDN博客&#xff09;。我自身也一直期望能留存些岁月的痕迹&#xff0c;然而却常困惑于不知哪些事物值得铭记&#xff0c;哪些又应被永远忘却。 随着时光流转&#x…...

MySQL - 运维篇

一、日志 1. 错误日志 2. 二进制日志 3. 查询日志 记录了所有的增删改查语句以及DDL语句 4. 慢查询日志 二、主从复制 1. 概述 2. 原理 3. 搭建 三、分库分表 1. 介绍 2. Mycat概述 3. Mycat入门 4. Mycat配置 5. Mycat分片 6. Mycat管理及监控 四、读写分离 1. 介绍 2. 一…...

WebGIS开发及市面上各种二三维GIS开发框架对比分析

GIS前端开发是现代WebGIS应用开发中非常重要的一环&#xff0c;通过前端开发框架&#xff0c;可以实现地图展示、交互、分析等功能。本文将介绍当前市面上常用的GIS前端开发框架&#xff0c;并进行对比分析。 Leaflet Leaflet是一款轻量级的开源地图库&#xff0c;它提供了丰…...

[论文精读]TorWard: Discovery, Blocking, and Traceback of Malicious Traffic Over Tor

期刊名称&#xff1a;IEEE Transactions on Information Forensics and Security 发布链接&#xff1a;TorWard: Discovery, Blocking, and Traceback of Malicious Traffic Over Tor | IEEE Journals & Magazine | IEEE Xplore 中文译名&#xff1a;TorWard&#xff1a;…...

pytest - 多线程提速

import timedef test1_test1():time.sleep(1)assert 1 1, "11"def test1_test2():time.sleep(1)assert 1 1, "11" 上面2个函数&#xff0c;执行情况&#xff1a; 正常执行时&#xff0c;花费 2.08s2个进程执行时&#xff0c;花费 1.18s2个线程执行时&a…...

python中logging的用法

logging.error 是 Python logging 模块中的一个方法&#xff0c;专门用于记录错误级别&#xff08;ERROR&#xff09;的日志信息。logging 模块是 Python 提供的标准日志工具&#xff0c;用于生成各种级别的日志消息&#xff0c;并支持日志的格式化和存储。 logging.error 的基…...

【YOLO目标检测车牌数据集】共10000张、已标注txt格式、有训练好的yolov5的模型

目录 说明图片示例 说明 数据集格式&#xff1a;YOLO格式 图片数量&#xff1a;10000&#xff08;2000张绿牌、8000张蓝牌&#xff09; 标注数量(txt文件个数)&#xff1a;10000 标注类别数&#xff1a;1 标注类别名称&#xff1a;licence 数据集下载&#xff1a;车牌数据…...

gdb xterm 调试 openmpi 程序

1&#xff0c;编写编译一个openmpi程序 迭代计算 PI 的源程序&#xff1a; pi_reduce.c #include <stdio.h>#include <math.h> #include <mpi.h>double f(double); double f(double x) {return (4.0/(1.0x*x)); }int main(int argc, char* argv[]) {int d…...

【STM32】江科大STM32笔记汇总(已完结)

STM32江科大笔记汇总 STM32学习笔记课程简介(01)STM32简介(02)软件安装(03)新建工程(04)GPIO输出(05)LED闪烁& LED流水灯& 蜂鸣器(06)GPIO输入(07)按键控制LED 光敏传感器控制蜂鸣器(08)OLED调试工具(09)OLED显示屏(10)EXTI外部中断(11)对射式红外传感器计次 旋转编码器…...

Java基础扫盲(二)

想看Java基础扫盲&#xff08;一&#xff09;的可以观看我的上篇文章Java基础扫盲 目录 String为什么设计为不可变的 String有长度限制吗 为什么JDK9将String的char[]改为byte[] 泛型中K,T,V,E,Object,?等都代表什么含义 怎么修改一个类中使用了private修饰的String类型…...

兼容React的刮刮乐完整代码实现

需要兼容React的刮刮乐完整代码实现 在现代Web开发中&#xff0c;React作为一种流行的前端框架&#xff0c;为开发者提供了构建动态界面的强大工具。刮刮乐效果作为一种趣味性的用户交互&#xff0c;能够显著提升用户体验和参与度。本文将详细介绍如何在React项目中实现一个兼…...

PHP程序如何实现限制一台电脑登录?

PHP程序如何实现限制一台电脑登录&#xff1f; 可以使用以下几种方法&#xff1a; 1. IP地址限制&#xff1a;在PHP中&#xff0c;可以通过获取客户端的IP地址&#xff0c;然后与允许登录的IP地址列表进行比对。如果客户端的IP地址不在列表中&#xff0c;就禁止登录。 “php $…...

nodejs fs 模块的简介与相关案例

fs 文件系统模块 什么是 fs 文件系统模块&#xff1f; fs 模块是 Node.js 官方提供的、用来操作文件的模块。它提供了一系列的方法和属性&#xff0c;用来满足用户对文件的操作要求。* 例如&#xff1a; fs.readFile() 方法用来读取文件内容。fs.writeFile() 方法用来写入文…...

计算机毕业设计 基于Flask+Vue的博客系统 Python毕业设计 前后端分离 附源码 讲解 文档

&#x1f34a;作者&#xff1a;计算机编程-吉哥 &#x1f34a;简介&#xff1a;专业从事JavaWeb程序开发&#xff0c;微信小程序开发&#xff0c;定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事&#xff0c;生活就是快乐的。 &#x1f34a;心愿&#xff1a;点…...

基于SSH的酒店管理系统的设计与实现 (含源码+sql+视频导入教程)

&#x1f449;文末查看项目功能视频演示获取源码sql脚本视频导入教程视频 1 、功能描述 基于SSH的酒店管理系统拥有两种角色 管理员&#xff1a;房间管理、房型管理、客户管理、预定管理、入住管理&#xff08;到店入住、预定入住、正在入住&#xff09;、账单管理、会员管理…...

消息队列10:为RabbitMq添加连接池

环境&#xff1a; win11rabbitmq-3.8.17.net 6.0RabbitMQ.Client 6.8.1vs2022 安装RabbitMq环境参照&#xff1a; window下安装rabbitmqlinux下安装rabbitmq 问题&#xff1a;rabbitmq的c#客户端没有自带连接池&#xff0c;所以需要手动实现。 简易实现如下&#xff1a; usi…...