Python的并行(持续更新)
0. 参考:
- 《Python并行编程 中文版》https://python-parallel-programmning-cookbook.readthedocs.io/zh_CN/latest/index.html
1. 线程和进程:
- 进程可以包含多个并行运行的线程;
- 通常,操作系统创建和管理线程比进程更省CPU资源;
- 线程用于一些小任务,进程用于繁重的任务;
- 同一个进程下的线程共享地址空间和其他资源,进程之间相互独立;
2. 在Python中使用线程:
2.1 多线程简介:
- 线程是独立的处理流程,可以和系统的其他线程并行或并发地执行。
- 多线程可以共享数据和资源,利用所谓的共享内存空间。
- 每一个线程基本上包含3个元素:程序计数器,寄存器和栈。
- 线程的状态大体上可以分为
ready, running, blocked
。- 多线程编程一般使用共享内容空间进行线程间的通讯,这就使管理内容空间成为多线程编程的重点和难点。
- 线程的典型应用是应用软件的并行化。
- 相比于进程,使用线程的优势主要是性能。
2.2 threading
库实现多线程:
1. 如何定义一个线程 threading.Thread()
:
class threading.Thread(group=None, ## 一般设置为 None ,这是为以后的一些特性预留的target=None, ## 当线程启动的时候要执行的函数name=None, ## 线程的名字,默认会分配一个唯一名字 Thread-Nargs=(), ## 使用 tuple 类型给 target 传递参数kwargs={}) ## 使用 dict 类型给 target 传递参数
举例:
import threadingdef function(i):print("function called by thread %i\n" % i)return#threads = []
for i in range(5):t = threading.Thread(target=function, args=(i,)) ## 用 function 函数初始化一个 Thread 对象 t,并将参数 i 传入;#threads.append(t) t.start() ## 线程被创建后不会马上执行,需要手动调用 .start() 方法执行线程t.join() ## 阻塞调用 t 线程的主线程,t 线程执行结束,主线程才会继续执行
运行结果:
function called by thread 0function called by thread 1function called by thread 2function called by thread 3function called by thread 4
2. 如何确定当前线程 threading.current_thread().name
:
- 通常一个服务进程中有多个线程服务,负责不同的操作,所以对于线程的命名是很重要的;
- Python中每一个线程在被
Thread
被创建时都有一个默认的名字(可以修改);
举例:
import threading
import timedef first_func():print(threading.current_thread().name + str(" is Starting"))time.sleep(2)print(threading.current_thread().name + str("is Exiting"))returndef second_func():print(threading.current_thread().name + str(" is Starting"))time.sleep(2)print(threading.current_thread().name + str("is Exiting"))returndef third_func():print(threading.current_thread().name + str(" is Starting"))time.sleep(2)print(threading.current_thread().name + str("is Exiting"))returnif __name__ == "__main__":t1 = threading.Thread(name="first_func", target=first_func)t2 = threading.Thread(name="second_func", target=second_func)t3 = threading.Thread(target=third_func)t1.start()t2.start()t3.start()t1.join()t2.join()t3.join()
运行结果:
first_func is Starting
second_func is Starting
Thread-36 (third_func) is Starting
first_funcis Exiting
second_funcis Exiting
Thread-36 (third_func)is Exiting
从上面运行结果可以看出,如果不用 name=
参数指定线程名称的话,那么线程名称将使用默认值。
3. 如何实现一个线程 threading
:
使用
threading
模块实现一个线程,需要3步:
- 定义一个
Thread
类的子类;- 重写
__init__(self, [,args])
方法;- 重写
run(self, [,args])
方法实现一个线程;
举例:
import threading
#import _thread
import time#exitFlag = 0class myThread(threading.Thread): ## 定义一个 threading 子类,继承 threading.Thread 父类def __init__(self, threadID, name, counter): ## 重写 __init__() 方法,并添加额外的参数threading.Thread.__init__(self) ## 初始化继承自Thread类的属性,使子类对象能够正确地继承和使用父类的属性和方法self.threadID = threadID ## 子类额外的属性self.name = nameself.counter = counterdef run(self):print("Starting " + self.name)print_time(self.name, self.counter, 5)print("Exiting " + self.name)def print_time(threadName, delay, counter):while counter:##if exitFlag: ## 当 exitFlag != 0时,执行 _thread.exit(),线程退出 (但是在该段代码中,exitFlag的值没有被改变,所以不会执行 _thread.exit(),所以可以直接注释掉)## _thread.exit()time.sleep(delay)print("%s: %s" % (threadName, time.ctime(time.time())))counter -= 1## 创建线程
thread1 = myThread(1, "Thread-1", 1)
thread2 = myThread(2, "Thread-2", 2)
## 开启线程
thread1.start()
thread2.start()
## .join()
thread1.join()
thread2.join()
print("Exiting Main Thread")
运行结果:
Starting Thread-1
Starting Thread-2Thread-1: Wed Jun 21 11:12:09 2023
Thread-2: Wed Jun 21 11:12:10 2023
Thread-1: Wed Jun 21 11:12:10 2023
Thread-1: Wed Jun 21 11:12:11 2023
Thread-2: Wed Jun 21 11:12:12 2023
Thread-1: Wed Jun 21 11:12:12 2023
Thread-1: Wed Jun 21 11:12:13 2023
Exiting Thread-1
Thread-2: Wed Jun 21 11:12:14 2023
Thread-2: Wed Jun 21 11:12:16 2023
Thread-2: Wed Jun 21 11:12:18 2023
Exiting Thread-2
Exiting Main Thread
由于 thread1 的 sleep 时间比 thread2 的时间短,所以 thread2 会执行更久一些,退出也就更晚一些。
4. 使用 Lock 进行线程同步 (lock()
):
- 并发线程中,多个线程对共享内存进行操作,并且至少有一个可以改变数据。这种情况下如果没有同步机制,那么多个线程之间就会产生竞争,从而导致代码无效或出错。
- 解决多线程竞争问题的最简单的方法就是用锁 (Lock)。当一个线程需要访问共享内存时,它必须先获得 Lock 之后才能访问;当该线程对共享资源使用完成后,必须释放 Lock,然后其他线程在拿到 Lock 进行访问资源。因此,为了避免多线程竞争的出现,必须保证:同一时刻只能允许一个线程访问共享内存。
- 在实际使用中,该方法经常会导致一种 死锁 现象,原因是不同线程互相拿着对方需要的 Lock,导致死锁的发生。
详见:https://python-parallel-programmning-cookbook.readthedocs.io/zh_CN/latest/chapter2/06_Thread_synchronization_with_Lock_and_Rlock.html
举例:
import threadingshared_resource_with_lock = 0
shared_resource_with_no_lock = 0
COUNT = 100000
shared_resource_lock = threading.Lock() ## 锁## 有锁的情况
def increment_with_lock():global shared_resource_with_lock ## shared_resource_with_lock 即最外面的 shared_resource_with_lock,这样写就不需要再通过函数的参数引入 shared_resource_with_lock 了for _ in range(COUNT):shared_resource_lock.acquire() ## 获取 锁shared_resource_with_lock += 1shared_resource_lock.release() ## 释放 锁def decrement_with_lock():global shared_resource_with_lockfor _ in range(COUNT):shared_resource_lock.acquire()shared_resource_with_lock -= 1shared_resource_lock.release()## 没有锁的情况
def increment_without_lock():global shared_resource_with_no_lockfor _ in range(COUNT):shared_resource_with_no_lock += 1def decrement_without_lock():global shared_resource_with_no_lockfor _ in range(COUNT):shared_resource_with_no_lock -= 1if __name__ == "__main__":t1 = threading.Thread(target=increment_with_lock)t2 = threading.Thread(target=decrement_with_lock)t3 = threading.Thread(target=increment_without_lock)t4 = threading.Thread(target=decrement_without_lock)## 开启线程t1.start()t2.start()t3.start()t4.start()## .join()t1.join()t2.join()t3.join()t4.join()print ("the value of shared variable with lock management is %s" % shared_resource_with_lock)print ("the value of shared variable with race condition is %s" % shared_resource_with_no_lock)
运行结果:
the value of shared variable with lock management is 0
the value of shared variable with race condition is 0
尽管在上面的结果中,没锁的情况下得到的结果也是正确的,但是执行多次,总会出现错误的结果;而有锁的情况下,执行多次,结果一定是正确的。
尽管理论上用锁的策略可以避免多线程中的竞争问题,但是可能会对程序的其他方面产生负面影响。此外,锁的策略经常会导致不必要的开销,也会限制程序的可扩展性和可读性。更重要的是,有时候需要对多进程共享的内存分配优先级,使用锁可能和这种优先级冲突。从实践的经验来看,使用锁的应用将对debug带来不小的麻烦。所以,最好使用其他可选的方法确保同步读取共享内存,避免竞争条件。
5. 使用RLock
进行线程同步:
- 为了保证 “只有拿到锁的线程才能释放锁”,那么应该使用
RLock()
对象;- 和
Lock()
一样,RLock()
也有acquire()
和release()
两种方法;RLock()
有三个特点:
1). 谁拿到谁释放。如果线程A拿到锁,线程B无法释放这个锁,只有A可以释放;
2). 同一线程可以多次拿到该锁,即可以acquire
多次;
3).acquire
多少次就必须release
多少次,只有最后一次release
才能改变RLock
的状态为unlocked);
举例:
import threading
import timeclass Box(object):lock = threading.RLock()def __init__(self):self.total_items = 0def execute(self, n):Box.lock.acquire()self.total_items += nBox.lock.release()def add(self):Box.lock.acquire()self.execute(1)Box.lock.release()def remove(self):Box.lock.acquire()self.execute(-1)Box.lock.release()def adder(box, items):while items > 0:print("adding 1 item in the box")box.add()time.sleep(1)items -= 1def remover(box, items):while items > 0:print("removing 1 item in the box")box.remove()time.sleep(1)items -= 1if __name__ == "__main__":items = 5print("putting %s items in the box"% items)box = Box()t1 = threading.Thread(target=adder, args=(box, items))t2 = threading.Thread(target=remover, args=(box, items))t1.start()t2.start()t1.join()t2.join()print("%s items still remain in the box " % box.total_items)
运行结果:
putting 5 items in the box
adding 1 item in the box
removing 1 item in the box
adding 1 item in the box
removing 1 item in the boxremoving 1 item in the box
adding 1 item in the boxremoving 1 item in the box
adding 1 item in the box
adding 1 item in the box
removing 1 item in the box0 items still remain in the box
Box
类的execute()
方法包含RLock
,adder()
和remover()
方法也包含RLock
,就是说无论是调用Box
还是adder()
或者remover()
,每个线程的每一步都有拿到资源、释放资源的过程。
6. 使用信号量进行线程同步:
- 信号量是由操作系统管理的一种抽象数据类型,用于多线程中同步对共享资源的使用;
- 信号量是一个内部数据,用于表明当前共享资源可以有多少并发读取;
- 在
Threading
中,信号量的操作有两个函数:acquire()
和release()
;
举例:
import threading
import time
import randomsemaphore = threading.Semaphore(0) ## 可以理解为一个内置的计数器,当调用 acquire 方法时候内置计数器 -1,对应着申请资源;调用 release 方法时候内置计数器+1,对应着释放可用资源。
print("init semaphore %s" % semaphore._value)def consumer():print("consumer is waiting.")semaphore.acquire()print("consumer notify: consumed item number %s" % item)print("consumer semaphore %s" % semaphore._value)def producer():global itemtime.sleep(10)item = random.randint(0, 1000)print("producer notify : produced item number %s" % item)semaphore.release()print("producer semaphore %s" % semaphore._value)if __name__ == "__main__":for _ in range(0, 5):t1 = threading.Thread(target=producer)t2 = threading.Thread(target=consumer)t1.start()t2.start()t1.join()t2.join()print("program terminated")
运行结果:
init semaphore 0
consumer is waiting.
producer notify : produced item number 756
producer semaphore 1
consumer notify: consumed item number 756
consumer semaphore 0
consumer is waiting.
producer notify : produced item number 948
producer semaphore 1
consumer notify: consumed item number 948
consumer semaphore 0
consumer is waiting.
producer notify : produced item number 597
producer semaphore 1
consumer notify: consumed item number 597
consumer semaphore 0
consumer is waiting.
producer notify : produced item number 239
producer semaphore 1
consumer notify: consumed item number 239
consumer semaphore 0
consumer is waiting.
producer notify : produced item number 141
producer semaphore 1
consumer notify: consumed item number 141
consumer semaphore 0
program terminated
根据semaphore = threading.Semaphore(0)
将信号量初始化为0,其目的在于同步两个或多个线程。
producer()
执行完后,通过seaphore.release()
释放资源,之后consumer()
通过semaphore.acquire()
拿到资源;
相应的信号量的计数器也会从初始化的0 --> 1 --> 多次重复。
信号量的一个特殊用法是互斥量,互斥量是初始值为1的信号量,可以实现数据、资源的互斥访问;
7. 使用条件进行线程同步:
- 条件:指的是程序状态的改变;
- 某些线程在等待某一条件发生,其他的线程会在该条件发生的时候进行通知。一旦条件发生,线程会拿到共享资源的唯一权限。
举例:
from threading import Thread, Condition
import timeitems = []
condition = Condition() ## A condition variable allows one or more threads to wait until they are notified by another thread.class consumer(Thread):def __init__(self):Thread.__init__(self)def consume(self):global conditionglobal itemscondition.acquire()if len(items) == 0:condition.wait() ## Wait until notified or until a timeout occurs.print("Consumer notify : no item to consume")items.pop()print("Consumer notify : consumed 1 item")print("Consumer notify : items to consume are " + str(len(items)))condition.notify() ## Wake up one or more threads waiting on this condition, if any.condition.release()def run(self):for _ in range(0, 20):time.sleep(2)self.consume()class producer(Thread):def __init__(self):Thread.__init__(self)def produce(self):global conditionglobal itemscondition.acquire()if len(items) == 10:condition.wait()print("Producer notify : items producted are " + str(len(items)))print("Producer notify : stop the production!!")items.append(1)print("Producer notify : total items producted " + str(len(items)))condition.notify()condition.release()def run(self):for _ in range(0, 20):time.sleep(1)self.produce()if __name__ == "__main__":producer = producer()consumer = consumer()producer.start()consumer.start()producer.join()consumer.join()
运行结果:
Producer notify : total items producted 1
Consumer notify : consumed 1 item
Consumer notify : items to consume are 0
Producer notify : total items producted 1
Producer notify : total items producted 2
Consumer notify : consumed 1 item
Consumer notify : items to consume are 1
Producer notify : total items producted 2
Producer notify : total items producted 3
Consumer notify : consumed 1 item
Consumer notify : items to consume are 2
Producer notify : total items producted 3
Producer notify : total items producted 4
Consumer notify : consumed 1 item
Consumer notify : items to consume are 3
Producer notify : total items producted 4
Producer notify : total items producted 5
Consumer notify : consumed 1 item
Consumer notify : items to consume are 4
Producer notify : total items producted 5
Producer notify : total items producted 6
Consumer notify : consumed 1 item
Consumer notify : items to consume are 5
Producer notify : total items producted 6
Producer notify : total items producted 7
Consumer notify : consumed 1 item
Consumer notify : items to consume are 6
Producer notify : total items producted 7
Producer notify : total items producted 8
Consumer notify : consumed 1 item
Consumer notify : items to consume are 7
Producer notify : total items producted 8
Producer notify : total items producted 9
Consumer notify : consumed 1 item
Consumer notify : items to consume are 8
Producer notify : total items producted 9
Producer notify : total items producted 10
Consumer notify : consumed 1 item
Consumer notify : items to consume are 9
Producer notify : total items producted 10
Consumer notify : consumed 1 item
Consumer notify : items to consume are 9
Consumer notify : consumed 1 item
Consumer notify : items to consume are 8
Consumer notify : consumed 1 item
Consumer notify : items to consume are 7
Consumer notify : consumed 1 item
Consumer notify : items to consume are 6
Consumer notify : consumed 1 item
Consumer notify : items to consume are 5
Consumer notify : consumed 1 item
Consumer notify : items to consume are 4
Consumer notify : consumed 1 item
Consumer notify : items to consume are 3
Consumer notify : consumed 1 item
Consumer notify : items to consume are 2
Consumer notify : consumed 1 item
Consumer notify : items to consume are 1
Consumer notify : consumed 1 item
Consumer notify : items to consume are 0
整个过程有点绕,可以通过这个例子简单理解 使用 condition 进行线程同步 (https://blog.csdn.net/lzanze/article/details/105351064)
8. 使用事件进行线程同步:
事件:线程之间用于通讯的对象。
举例:
import time
from threading import Thread, Event
import randomitems = []
event = Event()class consumer(Thread):def __init__(self, items, event):Thread.__init__(self)self.items = itemsself.event = eventdef run(self):while True:time.sleep(2)self.event.wait() ## 线程会阻塞在这里,直到事件 event 被触发(set.evet.set())才会继续执行。item = self.items.pop()print("Consumer notify : %d popped from list by %s" % (item, self.name))class producer(Thread):def __init__(self, items, event):Thread.__init__(self)self.items = itemsself.event = eventdef run(self):global itemfor _ in range(10):time.sleep(2)item = random.randint(0, 256)self.items.append(item) ## 将 item 添加到list末尾然后通过 self.event.set() 和 self.event.clear() 发出事件通知print('Producer notify : item %d appended to list by %s' % (item, self.name))print('Producer notify : event set by %s' % self.name)self.event.set() ## set() 方法将内部变量设置为 True (is_set() == True)print("Produce notify : event cleared by %s" % self.name)#print("Produce set event label : ", self.event.is_set())self.event.clear() ## clear() 方法将内部变量设置为 False (is_set() == False)#print("Produce clear event label : ", self.event.is_set())if __name__ == "__main__":t1 = producer(items, event)t2 = consumer(items, event)t1.start()t2.start()t1.join()t2.join()
运行结果(部分结果):
Producer notify : item 140 appended to list by Thread-64
Producer notify : event set by Thread-64
Produce notify : event cleared by Thread-64
Consumer notify : 140 popped from list by Thread-65
Producer notify : item 42 appended to list by Thread-64
Producer notify : event set by Thread-64
Produce notify : event cleared by Thread-64
Producer notify : item 101 appended to list by Thread-64
Producer notify : event set by Thread-64
Produce notify : event cleared by Thread-64
Consumer notify : 101 popped from list by Thread-65
Producer notify : item 213 appended to list by Thread-64
Producer notify : event set by Thread-64
Produce notify : event cleared by Thread-64
Producer notify : item 31 appended to list by Thread-64
Producer notify : event set by Thread-64
Produce notify : event cleared by Thread-64
Consumer notify : 31 popped from list by Thread-65
Producer notify : item 235 appended to list by Thread-64
Producer notify : event set by Thread-64
Produce notify : event cleared by Thread-64
该脚本我自己在运行的时候,运行了20多分钟,没结束,所以直接停了(部分结果如上所示)。
9. 使用 with
语法:
- 当两个相关的操作需要在一部分代码块前后分别执行的时候,可以使用
with
语法;- 使用
with
语法可以在特定的地方分配和释放资源,因此,with
语法也叫做“上下文管理器”;- 在
threading
模块中,所有带有acquire()
方法和release()
方法的对象(包括Lock, RLock, Condition, Semaphore
)都可以使用with
语法;
举例:
import threading
import logging
logging.basicConfig(level=logging.DEBUG, format="(%(threadName)-10s) %(message)s", )def threading_with(statement):with statement:logging.debug("%s acquired via with" % statement)def threading_not_with(statement):statement.acquire()try:logging.debug("%s acquired directly" % statement)finally:statement.release()if __name__ == "__main__":lock = threading.Lock()rlock = threading.RLock()condition = threading.Condition()mutex = threading.Semaphore(1)threading_synchronization_list = [lock, rlock, condition, mutex] ## 包含要测试的线程同步使用的对象for statement in threading_synchronization_list:t1 = threading.Thread(target=threading_with, args=(statement,))t2 = threading.Thread(target=threading_not_with, args=(statement,))t1.start()t2.start()t1.join()t2.join()
运行结果:
(Thread-68 (threading_with)) <locked _thread.lock object at 0x10ba04f00> acquired via with
(Thread-69 (threading_not_with)) <locked _thread.lock object at 0x10ba04f00> acquired directly
(Thread-70 (threading_with)) <locked _thread.RLock object owner=6223966208 count=1 at 0x10bca8740> acquired via with
(Thread-71 (threading_not_with)) <locked _thread.RLock object owner=6308098048 count=1 at 0x10bca8740> acquired directly
(Thread-72 (threading_with)) <Condition(<locked _thread.RLock object owner=6223966208 count=1 at 0x10bcf9080>, 0)> acquired via with
(Thread-73 (threading_not_with)) <Condition(<locked _thread.RLock object owner=6308098048 count=1 at 0x10bcf9080>, 0)> acquired directly
(Thread-74 (threading_with)) <threading.Semaphore object at 0x10760bf70> acquired via with
(Thread-75 (threading_not_with)) <threading.Semaphore object at 0x10760bf70> acquired directly
上述结果展示了使用with
和不用with
的每一个函数以及用在了哪些地方(Lock, RLock, Condition, Semaphore
)
10. 使用 queue
进行线程通信:
与
threading
模块相比,queue
操作更简单、更安全。
更新中……
相关文章:
Python的并行(持续更新)
0. 参考: 《Python并行编程 中文版》https://python-parallel-programmning-cookbook.readthedocs.io/zh_CN/latest/index.html 1. 线程和进程: 进程可以包含多个并行运行的线程;通常,操作系统创建和管理线程比进程更省CPU资源&am…...
chatgpt赋能python:Python实现Fibonacci数列
Python实现Fibonacci数列 Fibonacci数列是一个非常经典的数列,定义如下: F ( 0 ) 0 , F ( 1 ) 1 F(0)0, F(1)1 F(0)0,F(1)1 F ( n ) F ( n − 1 ) F ( n − 2 ) F(n)F(n-1)F(n-2) F(n)F(n−1)F(n−2) 也就是说,第n个数等于前两个数之和…...
开环模块化多电平换流器仿真(MMC)N=6
模型简介: 运行环境MATLAB2021a 开环模块化多电平换流器仿真(MMC)N=6,连接负载,采用载波移相调制。 可以得到换流器输出N+1=7电平的相电压波形。可考虑线路阻抗。 子模块采用半桥结…...
java springboot整合MyBatis联合查询
前面文章 java springboot整合MyBatis做数据库查询操作写了springboot整合MyBatis的方法 并演示了基础查询的语法 根据id查 那么 我们这次来演示联合查询 我们staff 表 内容如下 每条数据 对应的都有一个departmentid 这是 department部门表的外键id department表内容如下 如…...
windows2022证书配置.docx
Windows证书的配置 要求两台主机,一台作为域,一台进入域 按要求来选择角色服务 确认之后安装 安装完以后配置证书服务 选择服务 按要求配置 注:此处不用域用户登陆无法使用企业CA 按要求来 创建新的私钥 这几处检查无误后默认即可 有效期…...
HCIP网络笔记分享——IA回顾及OSPF协议
第一部分 HCIA回顾1、网络基础2、动态路由协议3、路由认证4、路由控制(AD metric ) 一、知识巩固二、场景模拟1、获取IP地址1.1 DHCP --- 动态主机配置协议1.1.1 DHCP客户端1.1.2 DHCP服务器1.1.3 DHCP客户端1.1.4 DHCP服务器 2、打开浏览器3、路由器进行…...
网络:IP地址、子网掩码、网络地址、广播地址、网段、网关
目录 一、IP地址 二、子网掩码 三、网络地址 四、广播地址 五、网段 六、网关 七、IP地址、子网掩码、网络地址、广指地址、网殷、网关的关系 参考链接 一、IP地址 IP地址是因特网协议(IP)中使用的一种数字标识符,用于唯一地标识网络…...
编程的未来 - 还有未来么?
缘起 唐门教主上个月某天深夜写了一篇博客 --《编程的未来》,要我谈谈感想。 这也是最近软件工程师们聊得比较多的问题,上周,在上海的 “关东小磨” 和十多位 CSDN 博主聚会的时候,大家也稍微谈了一下这个话题,但是谈…...
从零开始搭建群众权益平台(二)
这篇文章我们要建立的群众权益维护平台需要提供用户注册、登录、提交和查看问题或建议的功能,并且支持电话短信登录。在这个过程中,我们需要存储用户的登录信息。 我们将使用Node.js和Express.js作为后端框架,MongoDB作为数据库,并且使用Twilio服务发送短信验证码来实现手…...
Mysql之数据备份
一.日志 1.MySQL 的日志默认保存位置为 /usr/local/mysql/data2.修改日志配置文件 vim /etc/my.cnf [mysqld] ##错误日志,用来记录当MySQL启动、停止或运行时发生的错误信息,默认已开启 log-error/usr/local/mysql/data/mysql_error.log #指定日志的…...
【数据库数据恢复】SQL Server数据表结构损坏的数据恢复案例
数据库故障&分析: SQL server数据库数据无法读取。 经过初检,发现SQL server数据库文件无法被读取的原因是因为底层File Record被截断为0,无法找到文件开头,数据表结构损坏。镜像文件的前面几十M空间和中间一部分空间被覆盖掉…...
C语言/C++ 之 打飞机游戏
【项目简介】 1、设计思想:本项目主要是为了实现打飞机游戏,主要包括5个函数模块,和1个主函数框架。分别是chu_shi_hua();、you_cao_zuo;、wu_cao_zuo();、show();、main();等。项目完成过程中主要运用了C/C中的输入输…...
在 Docker 中部署 Mino 并挂载配置文件
创建本地目录 首先,在主机上创建一个目录,用于存放 Mino 的配置文件。例如,创建一个名为 mino 的目录,用于存放 Mino 的配置文件。 mkdir mino拉取 Mino 镜像 使用以下命令从 Docker Hub 上拉取 Mino 的最新镜像: …...
无限脉动:释放音乐和区块链在音乐领域的力量
音乐是一种永恒的通用语言,它将人们聚集在一起,超越了边界,在我们灵魂深处产生共鸣,创造联系。在当今数字时代,随着区块链技术和去中心化网络的出现,音乐世界正在经历一场深刻的变革。 我们在与艺术家合作&…...
读发布!设计与部署稳定的分布式系统(第2版)笔记09_一窝蜂和容量
1. 停电事故后电力恢复的方式 1.1. 停电后常见的情形是,送电几秒钟后又再次断电 1.2. 数百万台空调和冰箱的用电需求,使刚刚恢复的电力供应发生过载 1.3. 当电力供应不足时,增加的电流很快就到达满负荷,导致过载,触…...
详解java定时任务
在我们编程过程中如果需要执行一些简单的定时任务,无须做复杂的控制,我们可以考虑使用JDK中的Timer定时任务来实现。下面LZ就其原理、实例以及Timer缺陷三个方面来解析java Timer定时器。 一、简介 在java中一个完整定时任务需要由Timer、TimerTask两个…...
PCIe卡设计方案:单路12Gsps 3G 带宽模拟信号源PCIe卡
一、板卡概述 单路3G带宽模拟信号源卡由DA子卡和PCIe底板组成,二者通过标准FMC连接器互联,可以实现将PCIe总线数据转换为一路高速的模拟量输出。北京太速科技板可广泛用于雷达、通信、光电领域的噪声信号、毛刺、脉冲信号模拟产生等领域。 二、 …...
第1章 计算机网络和因特网
1、主机或端系统通过( )接入因特网。 A. ISPB. 调制解调器C. 交换机D. 路由器 P21:端系统(PC、智能手机、Web 服务器、电子邮件服务器等)经过一个接入 ISP 与因特网相连。 2、主机一般被划分为两类:客…...
QT入门基础知识
什么是QT QT是一个跨平台的C图像用户界面应用程序框架QT在1991年由奇趣科技开发QT的优点 跨平台,几乎支持所有平台接口简单,容易上手一定程度上简化了内存回收机制有很好的社区氛围可以进行嵌入式开发 QWidget QT注意事项 命名规范 类名 首字母大写,单…...
Leetcode---350周赛
题目列表 6901. 总行驶距离 6890. 找出分区值 6893. 特别的排列 6447. 给墙壁刷油漆 一、总行驶距离 很显然,这题单纯就是一道数学应用题,我们要明白最关键的一点 :只有当mainTank>5并且additionalTank>0时,才能发生副油…...
Django通过Nginx和uWSGI实现负载均衡
Django是一款非常流行的Web应用程序框架,它允许开发人员以快速、简单和灵活的方式构建可扩展和可维护的Web应用程序。当你的应用程序开始变得越来越受欢迎时,你可能会发现需要使用负载均衡来确保应用程序的可用性和性能。在本文中,我们将介绍…...
单元测试框架——Junit5
文章目录 Junit1. 注解2.断言3.测试用例执行顺序4.测试套件Suite1) 指定多个类2) 指定包 5. 参数化1) 单参数2) 多参数3) 文件注入 6.动态参数 Junit Junit是一个开源的用于Java语言的单元测试框架,也是Java方向使用最广泛的单元测试框架。 在pom.xml中引入Junit5…...
centos 系列添加 yum 源
nginx 首先,安装 EPEL (Extra Packages for Enterprise Linux) 仓库。这是一个由 Fedora 项目提供的免费扩展软件包仓库,其中包含许多有用的软件包。 sudo yum install epel-release 接下来,导入 Nginx 的官方 GPG 密钥,以便验证安…...
[Hive高级特性与 DDL和DML语法]
目录 🎇前言: 🎇 HiveQL语言的基本语法,包括DDL和DML两个方面。 🎇DDL(数据定义语言): 🎇DML(数据操作语言): 🎇 Hive高级特性 多种…...
Web服务器群集:Web基础与HTTP协议
目录 一、理论 1.Web基础 2.HTTP协议 二、实验 1.浏览本地HTML页面 三、总结 一、理论 1.Web基础 (1)域名和DNS ① 域名 网络是基于TCP/IP 协议进行通信和连接的,每一台主机都有一个唯一的标识(固定的IP地 址࿰…...
cmd命令常用速记
cmd命令大全 常见的appwiz.cpl control calc 等,各类功能、设置、甚至是文件属性和系统版本,都可以通过命令的方式快速查看和操作,有助于我们的提高工作效率,具体见下文。 cmd命令:开始->运行->键入…...
Python网络爬虫基础进阶到实战教程
文章目录 认识网络爬虫HTML页面组成Requests模块get请求与实战效果图代码解析 Post请求与实战代码解析 发送JSON格式的POST请求使用代理服务器发送POST请求发送带文件的POST请求 Xpath解析XPath语法的规则集:XPath解析的代码案例及其详细讲解:使用XPath解…...
树莓派使用VNC、SSH、Xrdp等方式进行远程控制的方法和注意事项
下面来总结一下远程操控树莓派用到的三种方式及其注意事项,其实这三种方式对于所有的Linux系统来说都是适用的。 目录 一、ssh控制树莓派 1.开启 ssh服务方法一 2.开启 ssh服务方法二 二、VNC远程连接 三、xrdp远程连接 四、其他注意事项 一、ssh控制树莓派 S…...
C++ 第二弹封装-类和对象
目录 1.类的引入 2.类的定义方式 3.访问权限 4.封装 5.类也是作用域 6.类的实例化 7.如何求一个类的大小 8.this指针 9.默认成员函数 10.构造函数 11.析构函数 12.拷贝构造函数 13.赋值运算符重载 14.const的类成员 15初始化列表 16.static的类成员 17.友元 …...
浅析 GeoServer CVE-2023-25157 SQL注入
原创稿件征集 邮箱:eduantvsion.com QQ:3200599554 黑客与极客相关,互联网安全领域里 的热点话题 漏洞、技术相关的调查或分析 稿件通过并发布还能收获 200-800元不等的稿酬 更多详情,点我查看! 简介 GeoServer是一个开…...
如果网站不备案/最近的新闻事件
设置完Activity后要在layout文件夹写一个item来配置simple的控件。 <LinearLayout xmlns:android"http://schemas.android.com/apk/res/android" android:layout_width"match_parent" android:layout_height"match_parent" android:orientat…...
网站二维码链接怎么做/北京百度搜索排名优化
2019独角兽企业重金招聘Python工程师标准>>> 按照libevent的文档,使用VC的nmake -f Makefile.nmake即可编译32位release模式。 因为项目中要求编译64位的版本,需要在Makefile.nmake中添加一个LIBFLAGS选项 /MACHINE:X64 如果要加调试信息&…...
wordpress导航分类怎么添加new/百度seo排名优化技巧分享
一.运动 1.每天必须运动30分钟以后,温和的有氧运动,活动全身 2.每隔1个半小时,起身活动腰部,颈部,肩部 3.经常活动手指,由于手指长期握鼠标,会造成末梢神经炎 4.经常眨眼睛,可以缓解眼部肌肉的紧张,而且促进眼部血液流通,是眼睛表面更加湿润,减少干涩,有效的保护眼睛 5.点…...
网站制作与网页制作/成都seo优化推广
Nacos除了服务的注册发现之外,还整合了配置中心。 通过Nacos的配置管理功能,可以将整个架构体系内的所有配置都集中在Nacos中存储。 改造nacos-provider如下 1、pom.xml <?xml version"1.0" encoding"UTF-8"?> <proje…...
网站实现多模板切换/网站有吗免费的
这是bootCDN上引用的bootstrap前端框架套件,由多个框架组合而成,方便平时学习和测试使用。生产环境要仔细琢磨一下,不要用开发版,而要用生产版。bootCDN的地址是:https://www.bootcdn.cn/ ,是由bootstrap中…...
盘锦网站建设制作/seo技术优化整站
/dev/ 设备目录/etc/ 系统配置及服务配置文件、启动命令的目录/proc 显示内核及进程信息的虚拟文件系统/tmp 临时文件目录,公共厕所。/home 普通用户的家目录。/root 超级管理员的家目录。/var 变化的目录,一般是日志文件ÿ…...