持续坚持原创输出,点击蓝字关注我吧
1.并发与并行
并发可以充分地利用 CPU 资源,一般都会使用多线程实现。多线程的作用是提高任务的平均执行速度,但是会导致程序可理解性变差,编程难度加大。
关于对并发与并行的概念,大家可能一直比较混淆。
定义:并发指的是多个任务在同一时刻正在进行,但实际上只有一个任务在一段时间内被处理;并行指的是多个任务在同一时刻同时被处理。
时间:并发涉及的是任务的同时发生;并行涉及的是任务的同时处理。
实现:并发可以通过多线程实现,每个线程分别执行不同的任务;并行则需要多核处理器才能实现,多核处理器可以同时处理多个任务。
也可以通过举例说明二者的区别:
并发:一个人工作时候可以在写代码、听音乐和玩游戏三个任务中任意切换,但是你的大脑不能在同一时间处理任何两件事情。
并行:并行则是假如一个人有2个大脑,可以同时写代码、听音乐或玩游戏。
软件测试开发技术群
在并发环境下, 由于程序的封闭性被打破,出现了以下特点:
(1) 并发程序之间有相互制约的关系。直接制约体现为一个程序需要另一个程 序的计算结果,间接制约体现为多个程序竞争共享资源,如处理器、缓冲区等。
(2) 并发程序的执行过程是断断续续的。程序需要记忆现场指令及执行点。
(3) 当并发数设置合理并且 CPU 拥有足够的处理能力时,并发会提高程序的运行效率。
2.何为线程安全
线程安全是指程序的并发执行状态下,多个线程对共享数据进行操作时,不会因为线程交替执行和切换执行顺序,导致数据不一致、不合法或出现其他不确定状态。
为了实现线程安全,通常采用互斥机制,例如锁、信号量等,保证同一时刻只有一个线程访问共享数据,避免产生数据不一致的问题。
线程安全的核心理念就是“要么只读,要么加锁”。
3.如何理解锁
乐观锁假定其他事务不会对数据产生冲突,因此在修改数据之前不会对数据加锁。相反,它在修改数据时使用版本号或其他机制来检测冲突,如果发生冲突,则事务回滚。
悲观锁假定其他事务将对数据产生冲突,因此在访问数据时对数据加锁。悲观锁通常导致其他事务等待,直到锁被释放,因此它可能影响性能。
总的来说,乐观锁适用于并发性较高的环境,而悲观锁适用于并发性较低的环境,因为它更容易控制冲突。
下面是一个使用乐观锁的简单示例程序:
import time
class OptimisticLockExample:
def __init__(self, initial_value=0, version=0):
self.value = initial_value
self.version = version
def update(self, new_value, current_version):
if self.version != current_version:
raise Exception("Version conflict")
time.sleep(1) # Simulate a slow database update operation
self.value = new_value
self.version += 1
if __name__ == "__main__":
example = OptimisticLockExample()
# Transaction 1
current_version = example.version
try:
example.update(10, current_version)
print("Transaction 1 successfully updated the value to 10")
except Exception as e:
print("Transaction 1 failed:", str(e))
# Transaction 2
current_version = example.version
try:
example.update(20, current_version)
print("Transaction 2 successfully updated the value to 20")
except Exception as e:
print("Transaction 2 failed:", str(e))
上面的代码定义了一个类 OptimisticLockExample,该类具有两个属性:value 和 version。每次修改数据时,都会对当前的版本号进行检查,如果版本号不匹配,则会引发异常。
在代码的主程序中,创建了一个 OptimisticLockExample 对象,并尝试两次对该对象进行更新,打印出交易是否成功。
下面是一个使用悲观锁的简单示例程序:
import threading
import time
class PessimisticLockExample:
def __init__(self, initial_value=0):
self.value = initial_value
self.lock = threading.Lock()
def update(self, new_value):
with self.lock:
time.sleep(1) # Simulate a slow database update operation
self.value = new_value
if __name__ == "__main__":
example = PessimisticLockExample()
# Transaction 1
try:
example.update(10)
print("Transaction 1 successfully updated the value to 10")
except Exception as e:
print("Transaction 1 failed:", str(e))
# Transaction 2
try:
example.update(20)
print("Transaction 2 successfully updated the value to 20")
except Exception as e:
print("Transaction 2 failed:", str(e))
上面的代码定义了一个类 PessimisticLockExample,该类具有一个属性 value 和一个互斥锁 lock。每次修改数据时,都会使用 with 语句对锁进行上锁,保证同一时刻只有一个线程在修改数据。
在代码的主程序中,我们创建了一个 PessimisticLockExample 对象,并尝试两次对该对象进行更新,打印出交易是否成功。
- END -
下方扫码关注 软件质量保障,与质量君一起学习成长、共同进步,做一个职场最贵Tester!
后台回复【测开】获取测试开发xmind脑图
后台回复【加群】获取加入测试社群方式,领2T测试自学视频
往期推荐
聊聊工作中的自我管理和向上管理
经验分享|测试工程师转型测试开发历程
聊聊UI自动化的PageObject设计模式
细读《阿里测试之道》