• 简单线性回归————损失函数(假设b为0),观察w改变损失函数的情况


    当我们只取一个参数w的时候,b不存在,那么就观察损失函数的情况

    这里引用滑块的函数用来表是不同的w的值对函数的影响

    1. from matplotlib.widgets import Slider
    2. import matplotlib.pyplot as plt
    3. # 创建一个图形窗口和子图
    4. fig, ax = plt.subplots()
    5. # 定义滑块的初始值和范围
    6. initial_value = 0.0
    7. min_value = -50
    8. max_value = 500
    9. # 创建一个滑块控件
    10. slider_ax = plt.axes([0.25, 0.1, 0.65, 0.03]) #窗口的参数
    11. slider = Slider(slider_ax, 'w', min_value, max_value, valinit=initial_value)
    12. '''
    13. slider_ax:滑动窗口的大小
    14. min_value:窗口的达到的最小值
    15. max_value:窗口的达到的最大值
    16. valinit=(具体的值):窗口的初始位置
    17. '''
    18. # 定义更新函数
    19. def update(val):
    20. # 获取滑块的值
    21. slider_value = slider.val
    22. # 打印滑块的值
    23. print("Slider value:", slider_value)
    24. # 将更新函数与滑块控件关联
    25. slider.on_changed(update)
    26. # 显示图形
    27. plt.show()
    '
    运行

    如图当滑动蓝色的矩形的时候,会输出对应的坐标轴上的值

    首先初始化数据,并绘制初始的图:

    1. # 初始化数据
    2. x_train = np.array([1, 2, 3, 4, 5])
    3. y_train = np.array([200, 400, 500, 400, 500])
    4. #创建一个窗口和两个子图
    5. fig,ax = plt.subplots(1,2)
    6. plt.subplots_adjust(bottom = 0.25)
    7. #设置初始的w的值,因为绘制的是b = 0的情况(没有b),所有w就置为0
    8. initial_w = 0.0
    9. #绘制初始的预测结果
    10. y = initial_w * x_train
    11. line, = ax[0].plot(x_train, y, c='b', label='预测')
    12. ax[0].scatter(x_train,y_train,marker = 'X',c = 'r')
    13. #二次函数(J函数)
    14. w_range = np.arange(-50,501,1)
    15. y_range = compute(x_train,y_train,w_range)
    16. #创建函数图像
    17. lin ,= ax[1].plot(w_range,y_range,label = 'f = wx')
    18. ax[1].set_xlabel('W')
    19. ax[1].set_ylabel('dis')
    20. ax[0].legend()
    21. ax[1].legend()

    这里创建了一个画布的两个子图,分别表示初始预测的和对应的损失函数

    之后定义一个函数计算不同w值对应的损失函数

    1. def compute(x,y,w_array):
    2. arr = np.zeros_like(w_array)
    3. for j , w in enumerate(w_array):
    4. m = x.shape[0]
    5. tol = 0
    6. for i in range(m):
    7. tol += (w * x[i] - y[i]) ** 2
    8. arr[j] = (1/(2 * m)) * tol
    9. return arr
    '
    运行

    然后就是怎么去滑动:

    1. #更新函数
    2. def update(val):
    3. w = slider.val # 获取滑块的值
    4. # slider.val是用于获取滑块当前所处位置对应的数值的属性
    5. #当滑块到某一个数值的时候,通过slider.val来获取这个数值然后进行数据的更新和绘图
    6. y = w * x_train #获得y的最新的值
    7. line.set_ydata(y) # 更新图上的y值坐标
    8. # 删除上一次的差值记录(每次更新前都清空两个子图的所有内容,保证不会被上次的内容干扰到本次的绘图)
    9. for arrow in ax[0].patches:
    10. arrow.remove()
    11. for text in ax[0].texts:
    12. text.remove()
    13. for arrow in ax[1].patches:
    14. arrow.remove()
    15. for text in ax[1].texts:
    16. text.remove()
    17. # 以上常在需要动态更新图表时使用,
    18. # 特别是在与滑块(Slider)、按钮(Button)、单选按钮(RadioButtons)等
    19. # Matplotlib的交互式控件结合使用时
    20. for i in range(len(x_train)):
    21. #计算误差坐标
    22. dx = x_train[i] * 0.01
    23. dy = w * y_train[i] * 0.01
    24. # 设置误差线
    25. ax[0].annotate('', xy=(x_train[i], w * x_train[i]), xytext=(x_train[i], y_train[i]),
    26. arrowprops=dict(arrowstyle='->', connectionstyle='arc3', color='gray', lw=1),
    27. fontsize=8)
    28. # 设置误差
    29. error = np.abs(y_train[i] - w * x_train[i])
    30. ax[0].text(x_train[i] + dx, w * x_train[i] + dy, 'er:' + str(error), fontsize=8)
    31. # 在update函数中,获取与 w 最接近的索引
    32. nearest_index = np.abs(w_range - w).argmin()
    33. # 使用最接近的索引来确定箭头的位置
    34. ax[1].annotate('', xy=(w, 0), xytext=(w_range[nearest_index], y_range[nearest_index]),
    35. arrowprops=dict(arrowstyle='-', connectionstyle='arc3', color='gray', lw=1),
    36. fontsize=8)
    37. ax[1].annotate('', xy=(0, y_range[nearest_index]), xytext=(w_range[nearest_index], y_range[nearest_index]),
    38. arrowprops=dict(arrowstyle='-', connectionstyle='arc3', color='gray', lw=1),
    39. fontsize=8)
    40. ax[1].text(w, y_range[nearest_index], f'point:{(w, y_range[nearest_index])}', fontsize=8)
    41. fig.canvas.draw_idle() # 重画图像
    '
    运行

    当我们去滑动窗口的时候,要保证当前的图上只有当前的结果,不能有上次的结果去影响

    所以每次都要清空图上的内容:

    1. # 删除上一次的差值记录(每次更新前都清空两个子图的所有内容,保证不会被上次的内容干扰到本次的绘图)
    2. for arrow in ax[0].patches:
    3. arrow.remove()
    4. for text in ax[0].texts:
    5. text.remove()
    6. for arrow in ax[1].patches:
    7. arrow.remove()
    8. for text in ax[1].texts:
    9. text.remove()
    10. #以上常在需要动态更新图表时使用,
    11. #特别是在与滑块(Slider)、按钮(Button)、单选按钮(RadioButtons)等
    12. # Matplotlib的交互式控件结合使用时

    之后就是设计具体的滑动效果:

    1. dx = x_train[i] * 0.01 # 设置箭头位置
    2. dy = w * x_train[i] * 0.01
    3. #dx 和 dy 分别表示箭头在x和y方向上的偏移量。
    4. # 设置误差线
    5. ax[0].annotate('', xy=(x_train[i], w * x_train[i]), xytext=(x_train[i], y_train[i]),
    6. arrowprops=dict(arrowstyle='->', connectionstyle='arc3', color='gray', lw=1),
    7. fontsize=8)
    8. #使用 ax[0].annotate() 方法绘制误差箭头,该箭头从当前样本点的真实值位置指向当前样本点的预测值位置。
    9. # 这里使用了 arrowprops 参数来设置箭头的样式和属性。
    10. # 设置误差
    11. error = np.abs(y_train[i] - w * x_train[i])
    12. ax[0].text(x_train[i] + dx, w * x_train[i] + dy, 'er:'+str(error), fontsize=8)
    13. #使用 ax[0].text() 方法在误差箭头附近添加误差标签,标签内容为当前样本点的误差值。

    在Matplotlib中,ax.annotate() 是一个功能强大的函数,用于在图上添加注释。这个函数允许你在一个特定的数据坐标 (xy) 上放置文本,并可以指定一个箭头从 (xy) 指向另一个位置 (xytext)。这对于在图上解释或突出显示特定数据点非常有用。

    ax.annotate() 的基本语法如下:

    1. ax.annotate(text, xy, xytext=None, xycoords='data', textcoords=None,
    2. arrowprops=None, **kwargs)

     

    参数解释:

    • text:注释的文本内容。
    • xy:被注释的数据点坐标,通常是一个元组,如 (x, y)
    • xytext:注释文本的位置坐标,也是一个元组。如果为 None,则文本将直接位于 xy 指定的位置。
    • xycoordsxy 坐标系的类型,如 'data'(数据坐标)、'figure'(图形坐标)等。默认为 'data'
    • textcoordsxytext 坐标系的类型。如果为 'offset points',则 xytext 将被解释为从 xy 的偏移量(以点为单位)。
    • arrowprops:一个字典,用于定义箭头的属性,如箭头样式、颜色、线宽等。
    • **kwargs:其他关键字参数,如文本的字体、颜色等。

    在你给出的代码中,ax[0].annotate() 被用来从预测值 (x_train[i], w * x_train[i]) 指向实际值 (x_train[i], y_train[i]) 的位置,并显示一个箭头。这里 xy 是预测值的位置,而 xytext 实际上是实际值的位置(尽管通常 xytext 用于指定注释文本的位置,但在这里它实际上被用作箭头的起点)。

    为了更清晰地显示箭头的起点和终点,你可能想要将 xytext 设置为一个稍微偏离实际值 y_train[i] 的位置,以避免箭头与实际值的数据点重叠。同时,通过 dx 和 dy 的使用,你已经尝试对文本位置进行了微调。

    最后,arrowprops 字典定义了箭头的样式和属性,如箭头样式 arrowstyle='->'、连接样式 connectionstyle='arc3'、颜色 color='gray' 和线宽 lw=1

    在Matplotlib中,ax.text() 方法用于在坐标轴上添加文本。这个方法允许你指定文本的位置、内容以及其他属性,如字体、颜色等。

    ax.text() 的基本语法如下

    ax.text(x, y, s, fontdict=None, **kwargs)
    • xy:文本的位置坐标,通常是数据坐标(即x轴和y轴上的值)。
    • s:要添加的文本内容。
    • fontdict:一个字典,用于定义文本的字体属性,如字体名称、大小、颜色等。如果未提供,则使用当前的默认字体属性。
    • **kwargs:其他关键字参数,用于定义文本的其他属性,如旋转角度、对齐方式等。

    在你给出的代码中,ax[0].text() 被用来在每个数据点上添加表示误差的文本。具体地,你计算了每个数据点的实际值与预测值之间的误差,并将误差的绝对值以文本形式显示在图上。文本的位置是通过在数据点的x坐标和预测值的y坐标上添加小的偏移量(dx 和 dy)来确定的,以避免文本与数据点重叠。

    eg:这是一个示例,展示了如何使用 ax.text() 在图上添加文本:

    1. import matplotlib.pyplot as plt
    2. import numpy as np
    3. # 假设有一些数据点
    4. x_train = np.linspace(0, 10, 10)
    5. y_train = 3 * x_train + 2 # 假设的线性关系
    6. w = 2.5 # 假设的权重
    7. # 创建一个图形和坐标轴
    8. fig, ax = plt.subplots(1, 1)
    9. # 绘制数据点
    10. ax.scatter(x_train, y_train, label='Data')
    11. # 绘制线性拟合线(这里只是一个示例,实际上应该使用拟合得到的权重)
    12. ax.plot(x_train, w * x_train, 'r-', label='Fit')
    13. # 添加文本以显示误差
    14. for i in range(len(x_train)):
    15. # 计算误差
    16. error = np.abs(y_train[i] - w * x_train[i])
    17. # 为文本添加小的偏移量以避免重叠
    18. dx = x_train[i] * 0.01
    19. dy = (w * x_train[i]) * 0.01
    20. # 添加文本
    21. ax.text(x_train[i] + dx, w * x_train[i] + dy, f'er:{error:.2f}', fontsize=8)
    22. # 添加图例和标签
    23. ax.legend()
    24. ax.set_xlabel('X')
    25. ax.set_ylabel('Y')
    26. # 显示图形
    27. plt.show()
    '
    运行

    在这个示例中,我们为每个数据点添加了一个文本标签,显示该点的预测误差。注意我们使用了 f'er:{error:.2f}' 来格式化文本,这样误差值将以两位小数的形式显示。

    在损失函数上用w_range中与w最接近的元素的索引来进行数据的更新:

    1. # 在update函数中,获取与 w 最接近的索引
    2. nearest_index = np.abs(w_range - w).argmin()
    3. # 使用最接近的索引来确定箭头的位置
    4. ax[1].annotate('', xy=(w, 0), xytext=(w_range[nearest_index], y_range[nearest_index]),
    5. arrowprops=dict(arrowstyle='-', connectionstyle='arc3', color='gray', lw=1),
    6. fontsize=8)
    7. ax[1].annotate('', xy=(0, y_range[nearest_index]), xytext=(w_range[nearest_index], y_range[nearest_index]),
    8. arrowprops=dict(arrowstyle='-', connectionstyle='arc3', color='gray', lw=1),
    9. fontsize=8)
    10. ax[1].text(w, y_range[nearest_index], f'point:{(w, y_range[nearest_index])}', fontsize=8)
    11. fig.canvas.draw_idle() # 重画图像

    为什么要w_range中与w最接近的元素的索引呢?

    在NumPy中,np.abs(w_range - w).argmin() 这个表达式是用来找到数组 w_range 中与给定值 w 最接近的元素的索引。这个表达式的工作原理可以分为几个步骤来解释:

    1. 计算差值w_range - w 会对 w_range 数组中的每个元素与 w 做差,得到一个新的数组,其中的每个元素是原数组元素与 w 的差值。

    2. 取绝对值np.abs(...) 会取上一步得到的差值数组的绝对值。这是必要的,因为我们关心的是差值的大小,而不是差值的正负。取绝对值可以确保我们找到的是距离 w 最近的数值,而不是仅仅是小于或大于 w 的数值。

    3. 找到最小值的索引.argmin() 方法会返回绝对值数组中最小元素的索引。这个索引对应于 w_range 中与 w 最接近的元素。

    所以,np.abs(w_range - w).argmin() 整体上就是在找到 w_range 中与 w 数值上最接近的元素所对应的索引位置。这种方法在计算上非常高效,因为它利用了NumPy的向量化操作,避免了显式的循环遍历数组。

    最后关于几个小的方面:

    完整代码:

    1. import numpy as np
    2. import matplotlib.pyplot as plt
    3. from matplotlib.widgets import Slider
    4. def compute(x,y,w_array):
    5. arr = np.zeros_like(w_array)
    6. for j , w in enumerate(w_array):
    7. m = x.shape[0]
    8. tol = 0
    9. for i in range(m):
    10. tol += (w * x[i] - y[i]) ** 2
    11. arr[j] = (1/(2 * m)) * tol
    12. return arr
    13. #更新函数
    14. def update(val):
    15. w = slider.val # 获取滑块的值
    16. # slider.val是用于获取滑块当前所处位置对应的数值的属性
    17. #当滑块到某一个数值的时候,通过slider.val来获取这个数值然后进行数据的更新和绘图
    18. y = w * x_train #获得y的最新的值
    19. line.set_ydata(y) # 更新图上的y值坐标
    20. # 删除上一次的差值记录(每次更新前都清空两个子图的所有内容,保证不会被上次的内容干扰到本次的绘图)
    21. for arrow in ax[0].patches:
    22. arrow.remove()
    23. for text in ax[0].texts:
    24. text.remove()
    25. for arrow in ax[1].patches:
    26. arrow.remove()
    27. for text in ax[1].texts:
    28. text.remove()
    29. # 以上常在需要动态更新图表时使用,
    30. # 特别是在与滑块(Slider)、按钮(Button)、单选按钮(RadioButtons)等
    31. # Matplotlib的交互式控件结合使用时
    32. for i in range(len(x_train)):
    33. #计算误差坐标
    34. dx = x_train[i] * 0.01
    35. dy = w * y_train[i] * 0.01
    36. # 设置误差线
    37. ax[0].annotate('', xy=(x_train[i], w * x_train[i]), xytext=(x_train[i], y_train[i]),
    38. arrowprops=dict(arrowstyle='->', connectionstyle='arc3', color='gray', lw=1),
    39. fontsize=8)
    40. # 设置误差
    41. error = np.abs(y_train[i] - w * x_train[i])
    42. ax[0].text(x_train[i] + dx, w * x_train[i] + dy, 'er:' + str(error), fontsize=8)
    43. # 在update函数中,获取与 w 最接近的索引
    44. nearest_index = np.abs(w_range - w).argmin()
    45. # 使用最接近的索引来确定箭头的位置
    46. ax[1].annotate('', xy=(w, 0), xytext=(w_range[nearest_index], y_range[nearest_index]),
    47. arrowprops=dict(arrowstyle='-', connectionstyle='arc3', color='gray', lw=1),
    48. fontsize=8)
    49. ax[1].annotate('', xy=(0, y_range[nearest_index]), xytext=(w_range[nearest_index], y_range[nearest_index]),
    50. arrowprops=dict(arrowstyle='-', connectionstyle='arc3', color='gray', lw=1),
    51. fontsize=8)
    52. ax[1].text(w, y_range[nearest_index], f'point:{(w, y_range[nearest_index])}', fontsize=8)
    53. fig.canvas.draw_idle() # 重画图像
    54. # 初始化数据
    55. x_train = np.array([1, 2, 3, 4, 5])
    56. y_train = np.array([200, 400, 500, 400, 500])
    57. #创建一个窗口和两个子图
    58. fig,ax = plt.subplots(1,2)
    59. plt.subplots_adjust(bottom = 0.25)
    60. #设置初始的w的值,因为绘制的是b = 0的情况(没有b),所有w就置为0
    61. initial_w = 0.0
    62. #绘制初始的预测结果
    63. y = initial_w * x_train
    64. line, = ax[0].plot(x_train, y, c='b', label='预测')
    65. ax[0].scatter(x_train,y_train,marker = 'X',c = 'r')
    66. #二次函数(J函数)
    67. w_range = np.arange(-50,501,1)
    68. y_range = compute(x_train,y_train,w_range)
    69. #创建函数图像
    70. lin ,= ax[1].plot(w_range,y_range,label = 'f = wx')
    71. ax[1].set_xlabel('W')
    72. ax[1].set_ylabel('dis')
    73. ax[0].legend()
    74. ax[1].legend()
    75. # 创建一个滑块来表示不同的w的值,J函数的值
    76. slider_ax = plt.axes([0.25,0.1,0.65,0.03])
    77. slider = Slider(slider_ax,'w',-50,500,valinit=initial_w)
    78. #将更新函数与滑块关联
    79. slider.on_changed(update)
    80. plt.show()
    '
    运行

    结果:

    原版:

    1. import numpy as np
    2. import matplotlib.pyplot as plt
    3. from matplotlib.widgets import Slider
    4. """
    5. >>> 对于函数图像,w值改变,两点值改变,直线也改变,从w,b改变,但我们并没用改变b。
    6. """
    7. # 二次函数
    8. def compute(x, y, w_array):
    9. arr = np.zeros_like(w_array) # 创建一个与 w_array 相同形状的数组,用于存储每个 w 对应的误差
    10. for j, w in enumerate(w_array):
    11. m = x.shape[0] # 获取样本数量
    12. tol = 0
    13. for i in range(m):
    14. tol += (w * x[i] - y[i]) ** 2
    15. arr[j] = (1 / (2 * m)) * tol
    16. return arr
    17. #更新函数
    18. def update(val):
    19. w = slider.val # 获取滑块的值
    20. #slider.val是用于获取滑块当前所处位置对应的数值的属性
    21. '''
    22. 当滑块到某一个数值的时候,通过slider.val来获取这个数值然后进行数据的更新和绘图
    23. '''
    24. y = w * x_train #获得y的最新的值
    25. line.set_ydata(y) # 更新图上的y值坐标
    26. # 删除上一次的差值记录(每次更新前都清空两个子图的所有内容,保证不会被上次的内容干扰到本次的绘图)
    27. for arrow in ax[0].patches:
    28. arrow.remove()
    29. for text in ax[0].texts:
    30. text.remove()
    31. for arrow in ax[1].patches:
    32. arrow.remove()
    33. for text in ax[1].texts:
    34. text.remove()
    35. #以上常在需要动态更新图表时使用,
    36. #特别是在与滑块(Slider)、按钮(Button)、单选按钮(RadioButtons)等
    37. # Matplotlib的交互式控件结合使用时
    38. for i in range(len(x_train)):
    39. # 误差坐标
    40. dx = x_train[i] * 0.01 # 设置箭头位置
    41. dy = w * x_train[i] * 0.01
    42. #dx 和 dy 分别表示箭头在x和y方向上的偏移量。
    43. # 设置误差线
    44. ax[0].annotate('', xy=(x_train[i], w * x_train[i]), xytext=(x_train[i], y_train[i]),
    45. arrowprops=dict(arrowstyle='->', connectionstyle='arc3', color='gray', lw=1),
    46. fontsize=8)
    47. #使用 ax[0].annotate() 方法绘制误差箭头,该箭头从当前样本点的真实值位置指向当前样本点的预测值位置。
    48. # 这里使用了 arrowprops 参数来设置箭头的样式和属性。
    49. # 设置误差
    50. error = np.abs(y_train[i] - w * x_train[i])
    51. ax[0].text(x_train[i] + dx, w * x_train[i] + dy, 'er:'+str(error), fontsize=8)
    52. #使用 ax[0].text() 方法在误差箭头附近添加误差标签,标签内容为当前样本点的误差值。
    53. '''
    54. ax[1].annotate('', xy=(w, 0), xytext=(w, y_range[int(w)]),
    55. arrowprops=dict(arrowstyle='<-', connectionstyle='arc3', color='gray', lw=1),
    56. fontsize=8)
    57. ax[1].annotate('', xy=(0, y_range[int(w)]), xytext=(w, y_range[int(w)]),
    58. arrowprops=dict(arrowstyle='<-', connectionstyle='arc3', color='gray', lw=1),
    59. fontsize=8)
    60. '''
    61. # 在update函数中,获取与 w 最接近的索引
    62. nearest_index = np.abs(w_range - w).argmin()
    63. # 使用最接近的索引来确定箭头的位置
    64. ax[1].annotate('', xy=(w, 0), xytext=(w_range[nearest_index], y_range[nearest_index]),
    65. arrowprops=dict(arrowstyle='-', connectionstyle='arc3', color='gray', lw=1),
    66. fontsize=8)
    67. ax[1].annotate('', xy=(0, y_range[nearest_index]), xytext=(w_range[nearest_index], y_range[nearest_index]),
    68. arrowprops=dict(arrowstyle='-', connectionstyle='arc3', color='gray', lw=1),
    69. fontsize=8)
    70. ax[1].text(w, y_range[nearest_index], f'point:{(w, y_range[nearest_index])}', fontsize=8)
    71. fig.canvas.draw_idle() # 重画图像
    72. # 初始化数据
    73. x_train = np.array([1, 2, 3, 4, 5])
    74. y_train = np.array([200, 400, 500, 400, 500])
    75. # 创建一个图形窗口和子图
    76. fig, ax = plt.subplots(1, 2)
    77. plt.subplots_adjust(bottom=0.25)
    78. # 设置初始的 w 值
    79. initial_w = 0.0
    80. # 绘制初始的预测结果
    81. y = initial_w * x_train
    82. line, = ax[0].plot(x_train, y, c='b', label='Prediction')
    83. ax[0].scatter(x_train, y_train, marker='x', c='r')
    84. # 二次函数
    85. w_range = np.arange(-50, 501, 1)
    86. y_range = compute(x_train, y_train, w_range)
    87. # 创建二次函数图像
    88. lin, = ax[1].plot(w_range, y_range, label='f = wx')
    89. ax[1].set_xlabel('W')
    90. ax[1].set_ylabel('dis')
    91. ax[0].legend()
    92. ax[1].legend()
    93. #通常是右上角添加一个图例,其中包含了你为各个绘图元素指定的标签
    94. '''compute loss
    95. def compute_a(x, w):
    96. m = x.shape[0]
    97. y_temp = w * x
    98. res = 0
    99. for i in range(len(y_temp)):
    100. res += (1 / (2 * m)) * (y_temp[i] - y_train[i]) ** 2
    101. return res
    102. line_dis = ax[1].plot(initial_w, compute_a(x_train, initial_w), c='b', label='distance')
    103. '''
    104. # 创建一个滑块控件
    105. slider_ax = plt.axes([0.25, 0.1, 0.65, 0.03])
    106. slider = Slider(slider_ax, 'w', -50, 500, valinit=initial_w)
    107. # 将更新函数与滑块控件关联
    108. slider.on_changed(update)
    109. # 显示图形
    110. plt.show()
    '
    运行

    结果与上面大致一样

  • 相关阅读:
    Nexus【应用 01】上传jar包到私有Maven仓库的两种方法:手动 Upload 和 mvn deploy 命令(配置+操作流程)
    [论文] 基于轴向注意多尺度时频卷积网络的语音增强算法
    操作系统--进程概念
    【JavaEE】MyBatis 单表查询易错问题(添加后返回自增id,${}与#{},SQL注入,模糊查询)
    网络原理之TCP_IP_1
    多线程【thread】【queue储存、锁】【2】
    某银行软件测试笔试题,满分一百你能得多少分?
    【面试题 - springcloud】 Hystrix
    代理IP和Socks5代理在游戏领域的重要应用
    计算机毕业设计之java+springboot基于vue的网上书城管理系统
  • 原文地址:https://blog.csdn.net/qq_74847271/article/details/138752538