探索Python编程的技巧:多线程魔法、网络舞台、正则魔法阵与递归迷宫

news2024/12/22 22:15:20

一 多线程

1.1 进程和线程

  • 进程: 就是一个程序,运行在系统之上,称这个程序为一个运行进程,并分配进程ID方便系统管理。
  • 线程:线程是归属于进程的,一个进程可以开启多个线程,执行不同的工作,是进程的实际工作最小单位。
  • 操作系统中可以运行多个进程,即多任务运行
  • 一个进程内可以运行多个线程,即多线程运行

  • 进程之间是内存隔离的, 即不同的进程拥有各自的内存空间。
  • 线程之间是内存共享的,线程是属于进程的,一个进程内的多个线程之间是共享这个进程所拥有的内存空间的。
    在这里插入图片描述

1.2 并行、并发执行概念

  • 在Python中,多线程用于实现并行和并发执行任务。虽然多线程可以让你同时执行多个任务,但由于Python的全局解释锁(Global Interpreter Lock,GIL)的存在,多线程并不能实现真正的多核并行。然而,多线程仍然可以用于执行I/O密集型任务,因为在这些任务中,线程可能会在等待I/O操作完成时释放GIL,从而允许其他线程运行。

  • 并行执行:

    • 并行执行是指多个任务在同一时刻同时运行,各自独立地占用一个CPU核心。
    • 在Python中,由于GIL的存在,多线程并不适合用于CPU密集型任务的并行执行。
    • 多个进程同时在运行,即不同的程序同时运行,称之为:多任务并行执行
    • 一个进程内的多个线程同时在运行,称之为:多线程并行执行
  • 并发执行:

    • 并发执行是指多个任务交替执行通过快速切换执行任务的上下文来实现“同时”执行的错觉。
    • 这在处理I/O密集型任务时非常有效,因为线程可能会在等待I/O完成时让出CPU资源给其他线程。

1.3 多线程编程

  • 在Python中,可以使用threading模块来创建和管理多线程。

  • threading.Thread类可以创建一个线程对象,用于执行特定的任务函数。

  • threading.Thread类的一般语法和一些常用参数:

    thread_obj = threading.Thread(target=function_name, args=(), kwargs={}, daemon=False)
    # 启动线程
    thread_obj.start() 
    
  • target: 必需的参数用于指定线程要执行的函数(任务)。函数会在新线程中运行。

  • args: 可选参数用于传递给目标函数的位置参数,以元组形式提供。如果函数不需要参数,可以传递一个空元组或省略这个参数。

  • kwargs: 可选参数用于传递给目标函数的关键字参数,以字典形式提供。如果函数不需要关键字参数,可以传递一个空字典或省略这个参数。

  • daemon: 可选参数,布尔值,用于指定线程是否为守护线程。守护线程会在主线程结束时被终止,而非守护线程会等待所有线程完成后再终止。

  • 使用threading.Thread类创建线程对象并启动线程

import threading
import time

def print_numbers():
    for i in range(1, 6):
        print(f"Number: {i}")
        time.sleep(1)

def print_letters():
    for letter in ['a', 'b', 'c', 'd', 'e']:
        print(f"Letter: {letter}")
        time.sleep(1)

if __name__ == "__main__":
    thread1 = threading.Thread(target=print_numbers)
    thread2 = threading.Thread(target=print_letters)

    thread1.start()  # Start the first thread
    thread2.start()  # Start the second thread

    thread1.join()   # 用于阻塞当前线程,直到被调用的线程完成其执行
    thread2.join()   # 用于阻塞当前线程,直到被调用的线程完成其执行

    print("All threads completed")
  • 在这个示例中,创建了两个线程对象,每个线程对象都关联一个不同的任务函数(print_numbersprint_letters)。然后启动这两个线程,并等待它们完成。最后,我们输出一个提示,表示所有线程都已完成。

  • thread1thread2 是两个线程对象,而 thread1.join()thread2.join() 是在主线程中调用的。当调用这些方法时,主线程会阻塞,直到对应的线程(thread1thread2)完成了它们的执行。

  • thread1.join()thread2.join() 语句确保在两个子线程执行完成后,主线程才会输出 “All threads completed” 这条消息。如果不使用 join(),主线程可能会在子线程还没有完成时就继续执行,导致输出消息的时机不确定。

1.4 补充:join()方法

  • 在多线程编程中,join() 方法用于阻塞当前线程,直到被调用的线程完成其执行。具体来说,thread1.join() 表示当前线程(通常是主线程)会等待 thread1 线程完成后再继续执行。

  • 这种等待的机制可以确保主线程在所有子线程执行完成后再继续执行,从而避免可能出现的线程之间的竞争条件和不确定性。这在需要等待所有线程完成后进行进一步操作或获取线程执行结果时非常有用。

1.5 并行、并发实现演示

  • 并行执行多个任务演示:
import threading

def task1():
    print("Task 1 started")
    # ... some code ...
    print("Task 1 finished")

def task2():
    print("Task 2 started")
    # ... some code ...
    print("Task 2 finished")

if __name__ == "__main__":
    thread1 = threading.Thread(target=task1)
    thread2 = threading.Thread(target=task2)

    thread1.start()
    thread2.start()

    thread1.join()
    thread2.join()

    print("All tasks completed")

  • 并发执行演示:
import threading
import time

def task1():
    print("Task 1 started")
    time.sleep(2)  # Simulate I/O operation
    print("Task 1 finished")

def task2():
    print("Task 2 started")
    time.sleep(1)  # Simulate I/O operation
    print("Task 2 finished")

if __name__ == "__main__":
    thread1 = threading.Thread(target=task1)
    thread2 = threading.Thread(target=task2)

    thread1.start()
    thread2.start()

    thread1.join()
    thread2.join()

    print("All tasks completed")

1.6 Thread参数传递使用演示

  • 当使用threading.Thread创建线程对象时,可以通过argskwargsdaemon参数传递不同类型的信息给线程。
  • 以下是针对每种参数的示例:
  1. 使用 args 参数传递位置参数:
import threading

def print_numbers(start, end):
    for i in range(start, end + 1):
        print(f"Number: {i}")

if __name__ == "__main__":
    thread1 = threading.Thread(target=print_numbers, args=(1, 5))
    thread2 = threading.Thread(target=print_numbers, args=(6, 10))

    thread1.start()
    thread2.start()

    thread1.join()
    thread2.join()

    print("All threads completed")
  1. 使用 kwargs 参数传递关键字参数:
import threading

def greet(name, message):
    print(f"Hello, {name}! {message}")

if __name__ == "__main__":
    thread1 = threading.Thread(target=greet, kwargs={"name": "Alice", "message": "How are you?"})
    thread2 = threading.Thread(target=greet, kwargs={"name": "Bob", "message": "Nice to meet you!"})

    thread1.start()
    thread2.start()

    thread1.join()
    thread2.join()

    print("All threads completed")
  1. 使用 daemon 参数设置守护线程:
import threading
import time

def count_seconds():
    for i in range(5):
        print(f"Elapsed: {i} seconds")
        time.sleep(1)

if __name__ == "__main__":
    thread = threading.Thread(target=count_seconds)
    thread.daemon = True  # 设置线程为守护线程

    thread.start()

    # No need to join daemon threads, they will be terminated when the main thread ends
    print("Main thread completed")
  • 将线程 thread 设置为守护线程(daemon = True)。这意味着当主线程结束时,守护线程也会被终止,而无需使用 join() 等待它完成。

二 网络编程

2.1 Socket初识

  • Python的套接字(Socket)编程是一种基本的网络编程技术,它可以在网络上建立连接并进行数据传输。
  • socket (简称 套接字) 是进程之间通信一个工具,进程之间想要进行网络通信需要socket。Socket负责进程之间的网络数据传输,是数据的搬运工。
    在这里插入图片描述

2.2 客户端和服务端

  • 2个进程之间通过Socket进行相互通讯,就必须有服务端和客户端
    • Socket服务端:等待其它进程的连接、可接受发来的消息、可以回复消息
    • Socket客户端:主动连接服务端、可以发送消息、可以接收回复
      在这里插入图片描述

2.3 创建socket对象详解

  • 在创建套接字对象时,通常是可以不指定参数的。如果没有指定参数,将会使用默认的参数,这些参数在 socket 模块中预先定义。默认情况下,socket 函数将创建一个 IPv4 的流式套接字。

  • 例如,以下代码将创建一个默认的 IPv4 TCP 套接字:

    import socket
    
    # 创建一个默认的 IPv4 TCP 套接字
    default_socket = socket.socket()
    
    # 后续代码中可以使用 default_socket 进行操作
    
  • 这种方式在很多情况下都是适用的,特别是当你只需要一个简单的 IPv4 TCP 套接字时。

    socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    
    1. socket:Python 的内置套接字模块,它提供了在网络上进行通信的基本功能。
    2. socket.AF_INET:表示套接字地址簇(Address Family),用于指定套接字使用的地址类型。AF_INET 表示使用 IPv4 地址。还可以使用 AF_INET6 来表示 IPv6 地址。
    3. socket.SOCK_STREAM:表示套接字的类型。SOCK_STREAM 表示这是一个流式套接字,它基于 TCP 协议提供了可靠的、面向连接的、双向的数据流传输。
  • 综合起来,socket.socket(socket.AF_INET, socket.SOCK_STREAM) 创建了一个基于 IPv4 地址和 TCP 协议的流式套接字对象,你可以使用这个套接字对象来建立连接、发送和接收数据。

  • 如果需要创建基于 UDP 协议的套接字,可以使用 socket.SOCK_DGRAM,例如:

    udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    

2.4 accept()方法详解

  • accept() 方法是在服务器端套接字上调用的方法,用于接受客户端的连接请求。它会阻塞程序,直到有客户端尝试连接到服务器,然后返回一个新的套接字用于与该客户端进行通信,以及客户端的地址信息。

    client_socket, client_address = server_socket.accept()
    
    • accept():接受客户端的连接请求。当调用这个方法时,它会阻塞程序,直到有客户端连接到服务器。一旦有连接请求到达,该方法将返回两个值:一个是表示与客户端通信的新套接字对象,另一个是客户端的地址信息。
    • client_socket新创建的套接字对象,用于与连接的客户端进行通信(可以使用这个套接字来接收和发送数据)
    • client_address:元组类型,包含客户端的 IP 地址和端口号。例如,('192.168.1.100', 54321)
  • 一般来说,服务器在一个循环中使用 accept() 方法,以便能够接受多个客户端的连接。每当有新的客户端连接到服务器时,accept() 方法会返回一个新的套接字和客户端的地址,然后服务器可以将新套接字添加到连接池,与客户端进行通信。

  • 注意:accept() 方法在没有连接请求时会一直阻塞程序。如果你希望设置超时或者非阻塞的连接等待,你可以在创建服务器套接字后设置相应的选项。这样,在没有连接请求时调用 accept() 方法将立即返回,不会阻塞程序的执行。

  • 例如,在创建服务器套接字后可以使用以下代码将其设置为非阻塞模式:

    server_socket.setblocking(False)
    

2.5 发送信息方法详解

  • send() 方法和 sendall() 方法都用于在套接字上发送数据,但它们有一些不同之处。

send(data) 方法:

  • send() 方法是用于发送数据的基本方法,它接受一个字节流(bytes)作为参数,并尝试将数据发送到连接的对方。
  • 如果成功发送全部数据,该方法将返回发送的字节数。如果没有发送完全部数据,可能返回一个小于请求发送数据的字节数。
  • 如果在发送过程中出现问题(例如连接中断),send() 方法可能会引发异常。

sendall(data) 方法:

  • sendall() 方法也用于发送数据,但它更加健壮,会自动处理数据分片和重试。

  • 无论数据有多大,sendall() 方法会尽力将所有数据都发送出去,直到全部数据都被发送成功或发生错误。

  • 方法不会立即返回,而是在所有数据都发送成功后才返回 None。如果发生错误,它可能引发异常。

  • sendall() 方法在发送数据时会自动处理数据的分片,确保数据都被正确发送。

  • 在大多数情况下,如果想要简单地发送一小段数据,可以使用 send() 方法。然而,如果需要发送大量数据或者确保数据被完整、可靠地发送,那么使用 sendall() 方法会更好,因为它会自动处理数据分片和错误处理。

  • 使用 send() 方法:

    client_socket.send(b"Hello, server!")
    
  • 使用 sendall() 方法:

    data = b"Hello, server!"
    client_socket.sendall(data)
    

2.6 Socket编程演示

  • 服务器端代码:

    import socket
    
    # 1. 创建Socket对象
    server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    
    # 2. 绑定服务器地址和端口
    server_address = ('127.0.0.1', 12345)
    server_socket.bind(server_address)
    
    # 3. 开始监听端口 backlog=5 标识允许的连接数量,超出的会等待,可以不填,不填自动设置一个合理的值
    server_socket.listen(5)
    
    print("Waiting for a connection...")
    # 4. 接收客户端连接,获得连接对象
    client_socket, client_address = server_socket.accept()
    print(f"Connected to {client_address}")
    
    # 5. 客户端连接后,通过recv方法 接收并发送数据
    while True:
        data = client_socket.recv(1024).decode('utf-8')
        # recv接受的参数是缓冲区大小,一般给1024即可
        # recv方法的返回值是一个字节数组也就是bytes对象,不是字符串,可以通过decode方法通过UTF-8编码,将字节数组转换为字符串对象
        if not data:
            break
        print(f"Received: {data}")
        # 6. 通过client_socket对象(客户端再次连接对象),调用方法,发送回复消息
        msg = input("请输入你要和客户端回复的消息:")
        if msg == 'exit':
            break
        client_socket.sendall(msg.eccode("UTF-8"))
    
    # 7.关闭连接
    client_socket.close()
    server_socket.close()
    

  • 客户端代码:
    import socket
    
    # 1.创建socket对象
    client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    
    # 2.连接服务器地址和端口
    server_address = ('127.0.0.1', 12345)
    client_socket.connect(server_address)
    
    
    # 3.发送数据
    while True:
    	# 发送消息
    	msg = input("请输入要给服务端发送的消息:")
    	if msg == 'exit':
        	break
    	client_socket.sendall(msg.encode("UTF-8"))
    	# 4.接收返回消息
    	recv_data = client_socket.recv(1024)  # 1024是缓冲区的大小,一般1024即可。 同样recv方法是阻塞的      
    	print(f"服务端回复的消息是:{recv_data.decode('UTF-8')}")
    
    # 5.关闭连接
    client_socket.close()
    

三 正则表达式

3.1 正则表达式概述

  • 正则表达式,又称规则表达式(Regular Expression),是使用单个字符串来描述、匹配某个句法规则的字符串,常被用来检索、替换那些符合某个模式(规则)的文本。
  • 正则表达式就是使用:字符串定义规则,并通过规则去验证字符串是否匹配。
  • 比如,验证一个字符串是否是符合条件的电子邮箱地址,只需要配置好正则规则,即可匹配任意邮箱。通过正则规则: (^[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+$) 即可匹配一个字符串是否是标准邮箱格式

3.2 Python正则表达式使用步骤

  • 使用正则表达式的一些基本步骤和示例:
  1. 导入re模块:
import re
  1. 使用re.compile()编译正则表达式:
# `pattern_here`应该替换为实际正则表达式
pattern = re.compile(r'pattern_here')
  1. 使用编译后的正则表达式进行匹配:
text = "This is an example text for pattern matching."
result = pattern.search(text)
if result:
    print("Pattern found:", result.group())
else:
    print("Pattern not found.")

3.3 正则的基础方法

  • Python正则表达式,使用re模块,并基于re模块中基础方法来做正则匹配。

  • 匹配(Match):使用match()来从字符串的开头开始匹配。匹配成功返回匹配对象(包含匹配的信息),匹配不成功返回空

result = pattern.match(text)
  • 搜索(Search):使用search()来查找文本中的第一个匹配项。整个字符串都找不到,返回None
result = pattern.search(text)
  • 查找所有(Find All):使用findall()来找到所有匹配项,并返回一个列表。找不到返回空list: []
results = pattern.findall(text)
  • 替换(Replace):使用sub()来替换匹配项。
# `replacement`应该是希望替换匹配项的内容
new_text = pattern.sub(replacement, text)
  • 分割(Split):使用split()来根据匹配项分割字符串。
parts = pattern.split(text)
  • 在正则表达式中,你可以使用不同的元字符(例如.*+?[]()等)来构建复杂的模式,以便进行更精确的匹配。

  • 演示使用正则表达式从文本中提取所有的电子邮件地址

import re

text = "Contact us at: john@example.com or jane@example.org for more information."

pattern = re.compile(r'\b[\w.-]+@[\w.-]+\.\w+\b')
email_addresses = pattern.findall(text)

for email in email_addresses:
    print(email)

3.4 元字符匹配

  • 单字符匹配
    在这里插入图片描述
    示例:
    字符串 s = "itheima1 @@python2 !!666 ##itcast3"
  • 找出全部数字: re.findall(r '\d', s)
  • 字符串的r标记,表示当前字符串是原始字符串,即内部的转义字符无效而是普通字符
  • 找出特殊字符: re.findall(r '\W', s)
  • 找出全部英文字母:re.findall(r '[a-zA-Z]', s)
  • []内可以写:[a-zA-Z0-9] 这三种范围组合或指定单个字符如[aceDFG135]

  • 数量匹配
    在这里插入图片描述
  • 边界匹配
    在这里插入图片描述
  • 分组匹配
    在这里插入图片描述

四 递归

  • 递归是一种编程技术(算法),即方法(函数)自己调用自己的一种特殊编程写法。在Python中,可以使用递归来解决许多问题,特别是那些可以被分解为相同或类似子问题的问题。
    在这里插入图片描述

  • 在使用递归时,需要确保定义递归基(base case),这是递归结束的条件,以避免无限循环。每次递归调用都应该将问题规模减小,使其朝着递归基的条件靠近。

  • 使用递归计算阶乘:

    def factorial(n):
        if n == 0:
            return 1  # 递归基
        else:
            return n * factorial(n - 1)  # 递归调用
    
    num = 5
    result = factorial(num)
    print(f"The factorial of {num} is {result}")
    
    • factorial 函数通过不断地调用自身来计算阶乘。当 n 达到递归基条件 n == 0 时,递归结束,不再调用自身。
  • 然而,递归并不总是最有效的解决方法,因为它可能会导致函数调用的嵌套层数过深,从而消耗大量的内存和处理时间。在一些情况下,使用循环或其他方法可能更有效。

  • 在编写递归函数时,要确保递归调用朝着递归基靠近,避免陷入无限循环,同时考虑性能方面的问题。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/882786.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

剑指offer-2.1数组

数组 数组可以说是最简单的一种数据结构,它占据一块连续的内存并按照顺序存储数据。创建数组时,我们需要首先指定数组的容量大小,然后根据大小分配内存。即使我们只在数组中存储一个数字,也需要为所有的数据预先分配内存。因此数…

Kotlin实战之获取本地配置文件、远程Apollo配置失败问题排查

背景 Kotlin作为一门JVM脚本语言,收到很多Java开发者的青睐。 项目采用JavaKotlin混合编程。Spring Boot应用开发,不会发生变动的配置放在本地配置文件,可能会变化的配置放在远程Apollo Server。 问题 因为业务需要,需要增加一…

css学习1

1、样式定义如何显示元素。 2、样式通常保存至外部的css文件中。 3、样式可以使内容与表现分离。 4、css主要有两部分组成:选择器与一条或多条声明。 选择器通常为要改变的html元素,每条声明由一个属性和一个值组成。每个属性有一个值,属性…

Centos7.9上(离线)安装Gitlab

1、下载Gitlab的rpm安装包Index of /gitlab-ce/yum/el7/ | 清华大学开源软件镜像站 | Tsinghua Open Source Mirror 2、安装rpm -i gitlab-ce-10.0.0-ce.0.el7.x86_64.rpm,如果依赖缺失,yum安装即可 3、vi /etc/gitlab/gitlab.rb 配置external_url&…

超声波一体气象站的介绍

超声波一体气象站集风速、风向、温湿度、噪声采集、PM2.5和 PM10、CO2、大气压力、光照于一体,采用标准 ModBus-RTU 通信协议,RS485信号输出方式,通信距离可达 2000 米,数据能够通过 485 通信的方式上传至客户的监控软件或 PLC 组…

210、仿真-基于51单片机灭火小车超声波避障温度烟雾控制报警Proteus仿真设计(程序+Proteus仿真+配套资料等)

毕设帮助、开题指导、技术解答(有偿)见文未 目录 一、硬件设计 二、设计功能 三、Proteus仿真图 四、程序源码 资料包括: 需要完整的资料可以点击下面的名片加下我,找我要资源压缩包的百度网盘下载地址及提取码。 方案选择 单片机的选择 方案一&a…

Hlang社区-社区主页实现

文章目录 前言首页结构固定导航栏左侧导航itemitem标志头部推荐文章展示ITEM实现ToolTip完整实现首页完整实现前言 废话不多说,直接看到效果,这里的话是我们社区主页,不是产品宣传主页哈: 是的也许你已经发现了这个页面和某个网站长得贼像。没错是这样的,这个布局我确实…

利用OpenCV光流算法实现视频特征点跟踪

光流简介 光流(optical flow)是运动物体在观察成像平面上的像素运动的瞬时速度。光流法是利用图像序列中像素在时间域上的变化以及相邻帧之间的相关性来找到上一帧跟当前帧之间存在的对应关系,从而计算出相邻帧之间物体的运动信息的一种方法。…

如何将常用的jdbc方法封装起来???

你是否还在为每次新建项目连接数据库而烦恼???(教你一次代码,简单完成每次连接) 1.建立maven项目 还没下载安装或者不会建立maven项目的可以看这里哦:maven的下载安装与配置环境变量&#xff0…

android wifi扫描 framework层修改扫描间隔

frameworks/opt/net/wifi/service/java/com/android/server/wifi/ScanRequestProxy.java 这个也就是说前台应用可以在120s(2分钟) 扫描 4 次 * a) Each foreground app can request a max of* {link #SCAN_REQUEST_THROTTLE_MAX_IN_TIME_WINDOW_FG_APPS} scan every* {l…

05应用程序设计和文件操作

一、 给应用程序设置菜单栏 比如: 在qt中,如果想要使用菜单栏功能,那么界面的基类要选择QMainWindow,不能选择QWidget QDialog 实现菜单栏步骤如下: 第一步:在UI设计师,直接双击菜单栏 第二步:在UI设计师,修改文本内容和其他设置 进行设置 设置的效果图如下: …

ASP.NET WEB API通过SugarSql连接MySQL数据库

注意:VS2022企业版可以,社区版可能存在问题。实体名称和字段和数据库中的要一致。 1、创建项目,安装SqlSugarCore、Pomelo.EntityFrameworkCore.MySql插件 2、文件结构 2、appsettings.json { “Logging”: { “LogLevel”: { “Default”: …

Python工匠 | 全书要点汇总

前言 Python前前后后我学了好几遍了,了解了Python中的许多用法,但都为快速入门之类的教程,基于“要干什么 --> 怎么做”的模式学习。而在动手编程的过程中,我常常感觉心有所惑,于是决定更系统地去学习、了解Python知…

ROS学习笔记(三)---好用的终端Terminator

ROS学习笔记文章目录 01. ROS学习笔记(一)—Linux安装VScode 02. ROS学习笔记(二)—使用 VScode 开发 ROS 的Python程序(简例) 一、Terminator是什么? 在前面的学习中,为了运行hello.py我是在vscode频繁的点击运行窗口的“”号…

视频集中存储EasyCVR视频汇聚平台定制项目增加AI智能算法

安防视频集中存储EasyCVR视频汇聚平台,可支持海量视频的轻量化接入与汇聚管理。平台能提供视频存储磁盘阵列、视频监控直播、视频轮播、视频录像、云存储、回放与检索、智能告警、服务器集群、语音对讲、云台控制、电子地图、平台级联、H.265自动转码等功能。为了便…

BGP知识总结

目录 EGP和IGP的协议追求 EGP的协议追求 IGP的协议追求 BGP的特点 BGP数据包 BGP的工作过程 1、配置完成后 2、邻居关系建立后 3、收敛完成 BGP路由黑洞问题 BGP的防环机制 1、EBGP水平分割——解决EBGP环路 2、IBGP水平分割——解决IBGP环路由中的一种机制 BGP的…

SpringBoot中的可扩展接口

目录 # 背景 # 可扩展的接口启动调用顺序图 # ApplicationContextInitializer # BeanDefinitionRegistryPostProcessor # BeanFactoryPostProcessor # InstantiationAwareBeanPostProcessor # SmartInstantiationAwareBeanPostProcessor # BeanFactoryAware # Applicati…

ubuntu篇---配置FTP服务,本机和docker安装

ubuntu篇---配置FTP服务 一、本机安装1.1 安装FTP服务器软件1.2 配置FTP服务 二、docker安装(我用的这个)2.1 创建 目录2.2 启动脚本2.3 访问2.4 如何创建一个新的用户2.5 测试2.6 使用 一、本机安装 1.1 安装FTP服务器软件 ubuntu安装vsftp sudo apt…

TiDB数据库从入门到精通系列之三:在单机上模拟部署生产环境集群

TiDB数据库从入门到精通系列之三:在单机上模拟部署生产环境集群 一、准备环境二、实施部署1.下载并安装 TiUP2.声明全局环境变量3.安装 TiUP 的 cluster 组件4.如果机器已经安装 TiUP cluster,需要更新软件版本5.由于模拟多机部署,需要通过 r…

注意力机制-基础

注意力机制-基础 基础部分比较简单,全是搬运,主要介绍几个例子。 主要是搬运来的:动手学深度学习 心理学 人类的注意力是有限的、有价值和稀缺的资源。而环境中的干扰注意力的信息却并不少。 比如人类的视觉神经系统大约每秒收到 位的信息…