NS3学习——tcpVegas算法代码详解(2)

NS3学习——tcpVegas算法代码详解(1)-CSDN博客

目录

4.TcpVegas类中成员函数

(5) CongestionStateSet函数

(6) IncreaseWindow函数

1.检查是否启用 Vgas

2.判断是否完成了一个“Vegas 周期”

2.1--if:判断RTT样本数量是否足够

2.2--else:RTT 样本 > 2

2.2.1 if--diff > m_gamma 并且处于慢启动阶段

2.2.2 else if-- diff < m_gamma 并且处于慢启动阶段

2.2.3 else-- 进入拥塞避免阶段

2.2.3.1 --if diff > m_beta

2.2.3.2 --else if diff < m_alpha 

2.2.3.3 --else  m_alpha < diff < m_beta

2.2.4 --更新慢开始阈值

 2.3 --重置RTT计数与最小RTT

3.慢启动阶段判断

(7) GetName函数

(8) GetSsThresh函数


4.TcpVegas类中成员函数

(5) CongestionStateSet函数

void
TcpVegas::CongestionStateSet (Ptr<TcpSocketState> tcb,
                              const TcpSocketState::TcpCongState_t newState)
{
  NS_LOG_FUNCTION (this << tcb << newState);
  if (newState == TcpSocketState::CA_OPEN)
    {
      EnableVegas (tcb);
    }
  else
    {
      DisableVegas ();
    }
}

函数作用:根据TCP连接的拥塞状态来启用或者禁用Vegas算法。

函数体:检查传入的newState 参数值是否为:TcpSocketState::CA_OPEN(拥塞避免阶段),若是,则启用Vegas算法,TCP使用该算法来调整拥塞窗口的值;若不是,则停止使用Vegas。

TcpVegas 算法通常在拥塞避免阶段启用,因为此时网络已稳定,Vegas 可以通过动态调整拥塞窗口来更好地利用网络带宽,并避免网络拥塞。

(6) IncreaseWindow函数

void
TcpVegas::IncreaseWindow (Ptr<TcpSocketState> tcb, uint32_t segmentsAcked)
{
  NS_LOG_FUNCTION (this << tcb << segmentsAcked);

  if (!m_doingVegasNow)
    {
      NS_LOG_LOGIC ("Vegas is not turned on, we follow NewReno algorithm.");
      TcpNewReno::IncreaseWindow (tcb, segmentsAcked);
      return;
    }

  if (tcb->m_lastAckedSeq >= m_begSndNxt)
    { // A Vegas cycle has finished, we do Vegas cwnd adjustment every RTT.

      NS_LOG_LOGIC ("A Vegas cycle has finished, we adjust cwnd once per RTT.");
      m_begSndNxt = tcb->m_nextTxSequence;

      if (m_cntRtt <= 2)
        {  // We do not have enough RTT samples, so we should behave like Reno
          NS_LOG_LOGIC ("We do not have enough RTT samples to do Vegas, so we behave like NewReno.");
          TcpNewReno::IncreaseWindow (tcb, segmentsAcked);
        }
      else //m_cntRtt > 2
        {
          NS_LOG_LOGIC ("We have enough RTT samples to perform Vegas calculations");
          uint32_t diff;
          uint32_t targetCwnd;
          uint32_t segCwnd = tcb->GetCwndInSegments ();
          double tmp = m_baseRtt.GetSeconds () / m_minRtt.GetSeconds ();
          targetCwnd = static_cast<uint32_t> (segCwnd * tmp);
          NS_LOG_DEBUG ("Calculated targetCwnd = " << targetCwnd);
          NS_ASSERT (segCwnd >= targetCwnd); // implies baseRtt <= minRtt
          diff = segCwnd - targetCwnd;
          NS_LOG_DEBUG ("Calculated diff = " << diff);

          if (diff > m_gamma && (tcb->m_cWnd < tcb->m_ssThresh))
            {
              NS_LOG_LOGIC ("We are going too fast. We need to slow down and "
                            "change to linear increase/decrease mode.");
              segCwnd = std::min (segCwnd, targetCwnd + 1);
              tcb->m_cWnd = segCwnd * tcb->m_segmentSize;
              tcb->m_ssThresh = GetSsThresh (tcb, 0);
              NS_LOG_DEBUG ("Updated cwnd = " << tcb->m_cWnd <<
                            " ssthresh=" << tcb->m_ssThresh);
            }
          else if (tcb->m_cWnd < tcb->m_ssThresh)
            {     // Slow start mode
              NS_LOG_LOGIC ("We are in slow start and diff < m_gamma, so we "
                            "follow NewReno slow start");
              TcpNewReno::SlowStart (tcb, segmentsAcked);
            }
          else //tcb m_cWnd > m_ssThresh
            {     // Linear increase/decrease mode
              NS_LOG_LOGIC ("We are in linear increase/decrease mode");
              if (diff > m_beta)
               {
                  NS_LOG_LOGIC ("We are going too fast, so we slow down by decrementing cwnd");
                  segCwnd--;
                  tcb->m_cWnd = segCwnd * tcb->m_segmentSize;
                  tcb->m_ssThresh = GetSsThresh (tcb, 0);
                  NS_LOG_DEBUG ("Updated cwnd = " << tcb->m_cWnd <<
                                " ssthresh=" << tcb->m_ssThresh);
                }
              else if (diff < m_alpha)
                {
                  NS_LOG_LOGIC ("We are going too slow, so we speed up by incrementing cwnd");
                  segCwnd++;
                  tcb->m_cWnd = segCwnd * tcb->m_segmentSize;
                  NS_LOG_DEBUG ("Updated cwnd = " << tcb->m_cWnd <<
                                " ssthresh=" << tcb->m_ssThresh);
                }
              else //   m_alpha < diff < m_beta
                {
                  NS_LOG_LOGIC ("We are sending at the right speed");
                }
            } //else  tcb m_cWnd > m_ssThresh
          tcb->m_ssThresh = std::max (tcb->m_ssThresh, 3 * tcb->m_cWnd / 4);
          NS_LOG_DEBUG ("Updated ssThresh = " << tcb->m_ssThresh);
        } // else m_cntRtt > 2
      m_cntRtt = 0;
      m_minRtt = Time::Max ();
    } //if tcb->m_lastAckedSeq >= m_begSndNxt
  else if (tcb->m_cWnd < tcb->m_ssThresh)  //tcb->m_lastAckedSeq < m_begSndNxt
    {
      TcpNewReno::SlowStart (tcb, segmentsAcked);
    }
} //IncreaseWindow

函数体逻辑:

1.检查是否启用 Vgas

if (!m_doingVegasNow)
{
  // If Vegas is not on, we follow NewReno algorithm
  NS_LOG_LOGIC ("Vegas is not turned on, we follow NewReno algorithm.");
  TcpNewReno::IncreaseWindow (tcb, segmentsAcked);
  return;
}

如果 m_doingVegasNow 为 false,即 Vegas 算法没有启用,那么执行 NewReno 拥塞控制算法。如果 Vegas 启用,那么执行以下代码:

2.判断是否完成了一个“Vegas 周期”

if (tcb->m_lastAckedSeq >= m_begSndNxt)
{
  // A Vegas cycle has finished, we do Vegas cwnd adjustment every RTT.
  NS_LOG_LOGIC ("A Vegas cycle has finished, we adjust cwnd once per RTT.");
  m_begSndNxt = tcb->m_nextTxSequence;

如果 tcb->m_lastAckedSeq发送方成功接收到的最后一个已确认包的序列号)大于等于 m_begSndNxt( Vegas 周期开始时的发送序列号),则表示当前已经完成了一个 Vegas 周期,并且将 m_begSndNxt 更新为当前的 tcb->m_nextTxSequence,以便下次周期开始时使用新的序列号。执行以下代码:

补:在 Vegas 算法中,一个周期是指发送方根据当前 RTT(往返时延)计算并调整其拥塞窗口(cwnd)的过程。这个周期通常与 RTT 周期同步。

m_lastAckedSeq 的变化非常重要,它帮助判断一个周期是否已经完成。每当接收方成功确认一个数据包,m_lastAckedSeq 会更新,以便发送方能知道哪些数据包已经被接收并得到确认。

在每个周期开始时,m_begSndNxt 会被更新为 当前发送序列号,而这个序列号代表的是 下一个将要发送的数据包的起始字节序列号。
当接收到的 ACK 包的序列号大于等于 m_begSndNxt 时,说明当前周期的所有数据包已经被确认,当前周期结束。

每个周期(每个 RTT)执行一次 IncreaseWindow。

tcb->m_nextTxSequence 是当前即将发送的下一个数据包的序列号。将 m_begSndNxt 更新为 tcb->m_nextTxSequence 是为了确保下一个周期从正确的地方开始。

2.1--if:判断RTT样本数量是否足够
if (m_cntRtt <= 2)
{
  // We do not have enough RTT samples, so we should behave like Reno
  NS_LOG_LOGIC ("We do not have enough RTT samples to do Vegas, so we behave like NewReno.");
  TcpNewReno::IncreaseWindow (tcb, segmentsAcked);
}

Vegas 需要足够的 RTT 样本才能做出可靠的拥塞窗口调整。

如果 RTT 样本数少于 2(即 m_cntRtt <= 2),它会退回到 NewReno 行为,这时会使用一个简单的慢启动和拥塞避免机制。

如果 RTT 样本 > 2,算法就会根据 Vegas 的逻辑调整cwnd值,同时执行else中的代码:

2.2--else:RTT 样本 > 2
else
{
  NS_LOG_LOGIC ("We have enough RTT samples to perform Vegas calculations");

计算目标拥塞窗口:

uint32_t diff;
uint32_t targetCwnd;
uint32_t segCwnd = tcb->GetCwndInSegments ();

double tmp = m_baseRtt.GetSeconds () / m_minRtt.GetSeconds ();
targetCwnd = static_cast<uint32_t> (segCwnd * tmp);
NS_LOG_DEBUG ("Calculated targetCwnd = " << targetCwnd);
NS_ASSERT (segCwnd >= targetCwnd); // implies baseRtt <= minRtt

Vegas 计算目标拥塞窗口(targetCwnd),首先获取当前拥塞窗口大小 segCwnd,然后根据 baseRtt(最小 RTT)和 minRtt(当前窗口内最小 RTT)来计算目标拥塞窗口。

如果 baseRtt 小于等于 minRtt,就可以安全计算目标窗口。

NS_ASSERT (segCwnd >= targetCwnd);

计算公式如下:  

targetCwnd=segCwnd*\frac{baseRtt}{minRtt}

计算实际拥塞窗口与目标窗口的差值:

diff = segCwnd - targetCwnd;
NS_LOG_DEBUG ("Calculated diff = " << diff);

 计算当前拥塞窗口与目标拥塞窗口之间的差值 diff。这个差值会决定是否需要调整拥塞窗口的大小。

2.2.1 if--diff > m_gamma 并且处于慢启动阶段

当前窗口的差值 diff 大于阈值 m_gamma,并且当前处于慢启动阶段(cwnd 小于 m_ssThresh)

if (diff > m_gamma && (tcb->m_cWnd < tcb->m_ssThresh))
{
  // We are going too fast. We need to slow down and change from
  // slow-start to linear increase/decrease mode by setting cwnd
  // to target cwnd. We add 1 because of the integer truncation.
  NS_LOG_LOGIC ("We are going too fast. We need to slow down and "
                "change to linear increase/decrease mode.");
  segCwnd = std::min (segCwnd, targetCwnd + 1);
  tcb->m_cWnd = segCwnd * tcb->m_segmentSize;
  tcb->m_ssThresh = GetSsThresh (tcb, 0);
  NS_LOG_DEBUG ("Updated cwnd = " << tcb->m_cWnd << " ssthresh=" << tcb->m_ssThresh);
}

m_alpha 和 m_beta 用于在正常的增速和减速中控制窗口的变化。m_gamma 是一个更大的阈值,通常用于判断网络是否发生了拥塞。

如果 diff > m_gamma,说明当前发送速率比目标速率快得多,且当前处于慢启动阶段。在慢启动阶段,cwnd 会急剧增长。如果在慢启动阶段的拥塞窗口已大于目标值,说明网络可能出现了拥塞的风险。

segCwnd = std::min(segCwnd, targetCwnd + 1):

调整当前cwnd,防止 segCwnd 超过目标窗口 targetCwnd,即避免发送方继续过快地发送数据。

由于 segCwnd 是以“段”为单位的(tcb->GetCwndInSegments()),加1的操作是为了避免整数截断。因为在计算过程中,通常会有一个小数部分,而加 1 可以保证计算结果向上取整,避免由于整数取整带来的问题。

比如,如果目标拥塞窗口是 targetCwnd = 5.4,由于取整的原因,segCwnd 可能被调整为 5,而加 1 后调整为 6。这样可以确保窗口不会太小,从而避免过早减速。

tcb->m_cWnd = segCwnd * tcb->m_segmentSize:

segCwnd 是拥塞窗口的大小(以段为单位)。
tcb->m_segmentSize 是每个 TCP 数据段的大小(字节数)。
segCwnd * tcb->m_segmentSize 得到的是字节级别的拥塞窗口大小,即实际可发送的数据量(以字节为单位)。通过这个公式,可以将段数(segCwnd)转换为字节数(tcb->m_cWnd),并调整发送窗口。

tcb->m_ssThresh = GetSsThresh(tcb, 0):

重新计算并设置新的慢启动阈值,用于控制从慢启动到拥塞避免阶段的过渡。

2.2.2 else if-- diff < m_gamma 并且处于慢启动阶段

当前的拥塞窗口小于慢启动阈值 m_ssThresh 并且 diff 小于 m_gamma

else if (tcb->m_cWnd < tcb->m_ssThresh)
{
  // Slow start mode
  NS_LOG_LOGIC ("We are in slow start and diff < m_gamma, so we "
                "follow NewReno slow start");
  TcpNewReno::SlowStart (tcb, segmentsAcked);
}

如果当前的拥塞窗口小于慢启动阈值 m_ssThresh,说明此时处于慢启动阶段。此时 diff 小于 m_gamma,表明网络没有拥塞,拥塞窗口仍然可以增长。

此时退回使用 NewReno 算法中的慢启动阶段,通过调用 TcpNewReno::SlowStart 来增加拥塞窗口。

2.2.3 else-- 进入拥塞避免阶段

当前的拥塞窗口大于慢启动阈值,tcb->m_cWnd 大于或等于 tcb->m_ssThresh

进入拥塞避免阶段,通过与目标 targetCwnd 的差值 diff 大小来选择是 增加窗口、减小窗口,还是 保持当前窗口。

else
{
  // Linear increase/decrease mode
  NS_LOG_LOGIC ("We are in linear increase/decrease mode");
2.2.3.1 --if diff > m_beta
if (diff > m_beta)
  {
    // We are going too fast, so we slow down
    NS_LOG_LOGIC ("We are going too fast, so we slow down by decrementing cwnd");
    segCwnd--;
    tcb->m_cWnd = segCwnd * tcb->m_segmentSize;
    tcb->m_ssThresh = GetSsThresh (tcb, 0);
    NS_LOG_DEBUG ("Updated cwnd = " << tcb->m_cWnd << " ssthresh=" << tcb->m_ssThresh);
  }
  • 这表示当前发送速率太快,实际的发送速率(segCwnd)已经超过了目标速率 targetCwnd。
  • 为了避免拥塞,减小 segCwnd,即减小拥塞窗口,从而减慢发送速率。
  • 减小后的 segCwnd 通过 tcb->m_cWnd = segCwnd * tcb->m_segmentSize; 更新。
  • 同时, 通过 GetSsThresh(tcb, 0) 更新慢启动阈值 tcb->m_ssThresh。
2.2.3.2 --else if diff < m_alpha 
 else if (diff < m_alpha)
  {
    // We are going too slow, so we speed up
    NS_LOG_LOGIC ("We are going too slow, so we speed up by incrementing cwnd");
    segCwnd++;
    tcb->m_cWnd = segCwnd * tcb->m_segmentSize;
    NS_LOG_DEBUG ("Updated cwnd = " << tcb->m_cWnd << " ssthresh=" << tcb->m_ssThresh);
  }
  • 这表示 当前发送速率太慢,实际的发送速率(segCwnd)低于目标速率 targetCwnd。
  • 为了加速数据传输,增加 segCwnd,即增大 拥塞窗口。
  • 增大的 segCwnd 同样通过 tcb->m_cWnd = segCwnd * tcb->m_segmentSize; 更新。
  • 在这种情况下,不需要调整慢启动阈值 tcb->m_ssThresh,因为它不会影响这一阶段的行为。
2.2.3.3 --else  m_alpha < diff < m_beta
else 
{
  NS_LOG_LOGIC ("We are sending at the right speed");
}
  • 这表示 当前发送速率合适,既不太快也不太慢,数据流量保持在理想状态。
  • 不需要对拥塞窗口做出调整,继续维持当前的速率。
2.2.4 --更新慢开始阈值
tcb->m_ssThresh = std::max (tcb->m_ssThresh, 3 * tcb->m_cWnd / 4);
NS_LOG_DEBUG ("Updated ssThresh = " << tcb->m_ssThresh);
  • 在(根据拥塞窗口和慢启动阈值大小比较)进行窗口调整之后,根据当前的拥塞窗口 tcb->m_cWnd 更新慢启动阈值(ssthresh)。
  • 计算公式 3 * tcb->m_cWnd / 4 是根据 Vegas 算法的设定,确保慢启动阈值不会过小。
  • 最终tcb->m_ssThresh 会被设置为 tcb->m_ssThresh 和 3 * tcb->m_cWnd / 4 中的较大值。这是为了确保慢启动阈值有足够的大小,避免在后续过程中频繁进入慢启动阶段。
 2.3 --重置RTT计数与最小RTT
m_cntRtt = 0;
m_minRtt = Time::Max ();
  • 由于每个周期结束都会重新进行 RTT 测量和窗口调整,所以需要重置 RTT计数(m_cntRtt)和最小RTT(m_minRtt)值。
  • m_cntRtt = 0:重置 RTT 样本计数器。
  • m_minRtt = Time::Max():将最小 RTT 重置为一个很大的值,确保下一周期开始时能够重新计算最小 RTT。

3.慢启动阶段判断

else if (tcb->m_cWnd < tcb->m_ssThresh)
{
    TcpNewReno::SlowStart(tcb, segmentsAcked);
}

在周期结束后,检查是否进入了慢启动阶段:

如果当前拥塞窗口 cwnd 小于慢启动阈值 ssThresh,则执行 NewReno 的慢启动算法,快速增长窗口。

注:如果tcb->m_lastAckedSeq < m_begSndNxt,表示当前 Vegas 周期没有结束,那么会进入 else if 判断,如果满足慢启动条件(tcb->m_cWnd < tcb->m_ssThresh),则会执行 NewReno 的慢启动算法。

为什么最后还要判断是否进入慢开始阶段?

如果 cwnd 小于 ssthresh,本应处于慢启动阶段,但由于没有判断 cwnd < ssthresh,程序会直接进入其他模式(如线性增加阶段)。这意味着即使 cwnd 还处于慢启动阶段,程序也会让它变得增长更慢。由于此时 cwnd 还较小,采用线性增长的方式会导致窗口增长太慢,无法迅速利用带宽,从而导致 网络利用率低,吞吐量上升的速度很慢,甚至不能充分利用网络的带宽。也就是说,可能会在不该进入线性增长阶段时就进入该阶段,从而导致 窗口增长速度过慢,降低网络利用率。

这个判断确保了在每个阶段执行适当的窗口调整策略,并帮助算法正确地处理不同网络状态下的拥塞控制。

(7) GetName函数

std::string
TcpVegas::GetName () const
{
  return "TcpVegas";
}

此函数主要用于标识 TCP 拥塞控制算法的类型,通过调用 GetName(),程序可以知道当前正在使用的是 TCP Vegas 算法。返回一个字符串,"TcpVegas"。

(8) GetSsThresh函数

uint32_t
TcpVegas::GetSsThresh (Ptr<const TcpSocketState> tcb,
                       uint32_t bytesInFlight)
{
  NS_LOG_FUNCTION (this << tcb << bytesInFlight);
  return std::max (std::min (tcb->m_ssThresh.Get (), tcb->m_cWnd.Get () - tcb->m_segmentSize), 2 * tcb->m_segmentSize);
}

} // namespace ns3

该函数的作用是计算和返回慢启动阈值(ssthresh)。

Ptr<const TcpSocketState>,指向当前连接的 TCP 套接字状态。TcpSocketState 中存储了关于当前 TCP 连接的许多信息,如拥塞窗口(m_cWnd)、慢启动阈值(m_ssThresh)等。
bytesInFlight:这通常表示当前已发送但尚未确认的数据量。这个参数在此函数中没有被直接使用。

tcb->m_ssThresh.Get():当前连接的慢启动阈值。
tcb->m_cWnd.Get() - tcb->m_segmentSize:计算拥塞窗口(cwnd)减去一个数据段的大小,表示如果当前 cwnd 足够大时,应该将 ssthresh 设置为接近这个值。
2 * tcb->m_segmentSize:这是 ssthresh 的最小值,表示即使拥塞窗口较小时,慢启动阈值也不会低于 2 * m_segmentSize。这个值是一个合理的下限,避免在拥塞窗口很小的时候,ssthresh 过小导致性能问题。

返回值:该函数通过 std::max() 和 std::min() 保证返回的 ssthresh 在合理的范围内:

std::min():确保 ssthresh 不会大于 cwnd - segmentSize,即不能超过当前拥塞窗口减去一个数据段的大小。
std::max():确保 ssthresh 不会小于 2 * segmentSize,即在任何情况下 ssthresh 至少为两个数据段大小。
最终返回值就是经过限制的 ssthresh,这是拥塞控制中切换模式的关键值。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【蓝桥杯——物联网设计与开发】拓展模块3 - 温度传感器模块

目录 一、温度传感器模块 &#xff08;1&#xff09;资源介绍 &#x1f505;原理图 &#x1f505;STS30-DIS-B &#x1f319;引脚分配 &#x1f319;通信 &#x1f319;时钟拉伸&#xff08;Clock Stretching&#xff09; &#x1f319;单次触发模式 &#x1f319;温度数据转…

项目2路由交换

背景 某学校为满足日常教学生活需求&#xff0c;推动数字校园的建设&#xff0c;学校有办公楼和学生宿舍楼和服务器集群三块区域&#xff0c;请合理规划IP地址和VLAN&#xff0c;实现企业内部能够互联互通现要求外网能通过公网地址访问服务器集群&#xff0c;学生和老师能正常…

计算机网络概要与习题

第1章 概论 1、计算机网络 2、互联网 3、计算机网络体系结构 分层模型 OSI/RM 7层模型 TCP/IP 5层模型 协议、PDU、SDU、SAP等术语 数据封装&#xff08;计算&#xff09; 第2章 数据通信基础 1、数据通信系统组成 2、主要性能指标 数据传输速率 码元速率 时延 …

使用VsCode编译调试Neo4j源码

文章目录 使用VsCode编译调试Neo4j源码1 简介2 步骤1 下载源码2 依赖3 构建Neo4j4 运行5 安装VsCode扩展6 **调试** 使用VsCode编译调试Neo4j源码 1 简介 Neo4j作为领先的图数据库&#xff0c;在存储、查询上都非常值得分析学习。通过调试、日志等方法跟踪代码工作流有助于理…

HTML-CSS(day01)

W3C标准&#xff1a; W3C&#xff08; World Wide Web Consortium&#xff0c;万维网联盟&#xff09; W3C是万维网联盟&#xff0c;这个组成是用来定义标准的。他们规定了一个网页是由三部分组成&#xff0c;分别是&#xff1a; 三个组成部分&#xff1a;&#xff08;1&…

Linux文件的压缩和解压

【图书推荐】《Ubuntu Linux系统管理与运维实战》_学ubuntu哪本书好-CSDN博客 【图书介绍】】几本Linux系统管理与运维图书_朱文伟 linux驱动-CSDN博客 《Ubuntu Linux系统管理与运维实战&#xff08;Linux技术丛书&#xff09;》(张春晓&#xff0c;肖志健)【摘要 书评 试读…

基于springboot的海洋知识服务平台的设计与实现

基于springboot的海洋知识服务平台的设计与实现 写在前面 需要源码加lzlv58787 开发内容 编程语言&#xff1a;Java / Vue2 框架&#xff1a; SpringBoot Shiro Mybatis-plus 项目结构 后端管理系统前台Web 后端管理系统 前台Web

论文解读 | EMNLP2024 一种用于大语言模型版本更新的学习率路径切换训练范式

点击蓝字 关注我们 AI TIME欢迎每一位AI爱好者的加入&#xff01; 点击 阅读原文 观看作者讲解回放&#xff01; 作者简介 王志豪&#xff0c;厦门大学博士生 刘诗雨&#xff0c;厦门大学硕士生 内容简介 新数据的不断涌现使版本更新成为大型语言模型&#xff08;LLMs&#xff…

【LeetCode】394、字符串解码

【LeetCode】394、字符串解码 文章目录 一、递归: 嵌套类问题1.1 递归: 嵌套类问题 二、多语言解法 一、递归: 嵌套类问题 1.1 递归: 嵌套类问题 // go func decodeString(s string) string {// 如果遇到 嵌套括号的情况, 则递归// 可能连续多位数字, 则 通过 cur cur * 10 …

iOS开发代码块-OC版

iOS开发代码块-OC版 资源分享资源使用详情Xcode自带代码块自定义代码块 资源分享 自提&#xff1a; 通过网盘分享的文件&#xff1a;CodeSnippets 2.zip 链接: https://pan.baidu.com/s/1Yh8q9PbyeNpuYpasG4IiVg?pwddn1i 提取码: dn1i Xcode中的代码片段默认放在下面的目录中…

微信小程序的轮播图学习报告

微信小程序轮播图学习报告 好久都没分享新内容了&#xff0c;实在惭愧惭愧。今天给大家做一个小程序轮播图的学习报告。 先给大家看一下我的项目状态&#xff1a; 很空昂&#xff01;像一个正在修行的老道&#xff0c;空的什么也没有。 但是我写了 4 个 view 容器&#xff0c;…

airflow docker 安装

mkdir -p /root/airflow cd /root/airflow && mkdir -p ./dags ./logs ./plugins ./configcd /root/airflow/ wget https://airflow.apache.org/docs/apache-airflow/2.10.4/docker-compose.yaml nano docker-compose.yamlAIRFLOW__CORE__LOAD_EXAMPLES: false #初始化…

Redis篇--常见问题篇7--缓存一致性2(分布式事务框架Seata)

1、概述 在传统的单体应用中&#xff0c;事务管理相对简单&#xff0c;通常使用数据库的本地事务&#xff08;如MySQL的BEGIN和COMMIT&#xff09;来保证数据的一致性。然而&#xff0c;在微服务架构中&#xff0c;由于每个服务都有自己的数据库&#xff0c;跨服务的事务管理变…

Linux x86_64离线安装Nginx全教程(含安装包)

最近在整理麒麟V10操作系统的常用中间件的安装今天也把之前的nginx一起整理一下&#xff0c;作为后续的笔记记录 1. 资源 百度网盘下载相关安装包包含信息如下截图 通过网盘分享的文件&#xff1a;nginx链接: https://pan.baidu.com/s/1r6SCnogqbhm-JOTPIjc6xA?pwdjuen 提取…

Python酷库之旅-第三方库Pandas(269)

目录 一、用法精讲 1276、pandas.tseries.offsets.BQuarterEnd.is_quarter_end方法 1276-1、语法 1276-2、参数 1276-3、功能 1276-4、返回值 1276-5、说明 1276-6、用法 1276-6-1、数据准备 1276-6-2、代码示例 1276-6-3、结果输出 1277、pandas.tseries.offsets.…

前端入门之VUE--ajax、vuex、router,最后的前端总结

前言 VUE是前端用的最多的框架&#xff1b;这篇文章是本人大一上学习前端的笔记&#xff1b;欢迎点赞 收藏 关注&#xff0c;本人将会持续更新。本人不是学前端的&#xff0c;这个是大一的时候上学的和做的笔记&#xff0c;那个时候学的也蒙&#xff0c;故这里对前端做一个总…

API-AI聊天替换网站

当你下载了API-AI聊天软件&#xff0c;但是不会用&#xff0c; Install Windows(PC) | Chatbox Releases ChatGPTNextWeb/ChatGPT-Next-Web GitHub 方法一 请看对应网站的介绍文档。 找到类似于这样说明文档&#xff0c;然后替换 方法二 或者找代码

Leetcode Hot 100 【二叉树】104. 二叉树的最大深度

104. 二叉树的最大深度 已解答 简单 相关标签 相关企业 给定一个二叉树 root &#xff0c;返回其最大深度。 二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。 示例 1&#xff1a; 输入&#xff1a;root [3,9,20,null,null,15,7] 输出&#xff1a;3…

Flink调优----资源配置调优与状态及Checkpoint调优

目录 第 1 章 资源配置调优 1.1 内存设置 1.1.1 TaskManager 内存模型 1、内存模型详解 2、案例分析 1.1.2 生产资源配置示例 1.2 合理利用 cpu 资源 1.2.1 使用 DefaultResourceCalculator 策略 1.2.2 使用 DominantResourceCalculator 策略 1.2.3 使用 DominantRes…

MySQL 常用程序介绍

以下是一些常用的MySQL程序&#xff1a; 程序名作⽤mysqldMySQL的守护进程即 MySQL 服务器&#xff0c;要使⽤MySQL 服务器 mysqld必须正在运⾏状态mysql MySQL客⼾端程序&#xff0c;⽤于交互式输⼊ SQL 语句或以批处理模式从⽂件执⾏SQL的命令⾏⼯具 mysqlcheck⽤于检查、修…