MIT-6.824-Lab2,Raft部分笔记|Use Go

2024-02-23 14:36
文章标签 use go 笔记 部分 mit lab2 raft 6.824

本文主要是介绍MIT-6.824-Lab2,Raft部分笔记|Use Go,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

      • 前记
      • Paper6:Raft
      • LEC5、6:Raft
      • LAB2
        • 2A
          • task
          • Hint
          • locking
          • structure
          • guide
          • 设计与编码
        • 2B
          • task
          • Hint
          • 设计与编码
        • 2C
          • task
          • Hint
        • question
        • 后记
      • LEC5:GO, Threads, and Raft
          • go threads技巧
          • raft实验易错点
          • debug技巧

前记

  • 趁着研一考完期末有点点空余时间,把Raft的实验补了
  • 记录着看视频、论文和实验过程中的一些想法

Paper6:Raft

概述(来自NewBing):

raft算法是一种用于分布式一致性的共识算法,旨在解决分布式系统中的领导者选举和日志复制等问题。它的设计目标是易于理解和实现,并且能够提供强一致性保证。raft算法的核心原理包括三个关键组件:领导者选举、日志复制和安全性。

  • 领导者选举:raft算法将时间划分为一个个的任期(term),每个任期的开始都是一次选举,一个或多个候选者(candidate)会尝试成为领导者(leader)。如果一个候选者赢得了大多数节点的投票,它就会成为新的领导者,并在该任期内管理整个集群。如果没有选出领导者,就会开始下一个任期,并重新进行选举。raft算法保证在任意时刻最多只有一个领导者。
  • 日志复制:领导者选出后,就开始接收客户端的请求,并将请求作为日志条目(log entry)加入到它的日志中,然后并行地向其他节点发送附加日志请求(AppendEntries RPC)复制日志条目。当这条日志被复制到大多数节点上,领导者就将这条日志应用到它的状态机,并向客户端返回执行结果。领导者会不断地重试附加日志请求,直到所有的节点都存储了所有的日志条目。
  • 安全性:raft算法增加了一些限制来保证安全性,即只有拥有最新的已提交的日志条目的节点才有资格成为领导者,而且领导者只能提交当前任期的日志条目,旧任期的日志条目要等到提交当前任期的日志条目来间接提交。这样可以避免已提交的日志条目被覆盖的情况。

有一个经验:要想在Raft中假设A情况,你首先得考虑A情况是否有可能发生。

细节点:

  1. Raft Basic

    1. Figure 2是非常重要的一个图。
    2. follower只接受请求,不主动发起请求
    3. 当client发送请求到follower时,会转发给ld处理
    4. ld会通过发送AE来抑制其他server发起选举。也就是说,ld不出错的话,它永远是ld。
    5. 当ld提交时,会通知follower
    6. term会通过包的发送来交换。如果接受者发现有更大的任期,那么它会更新自己的任期。如果发现更小term的包,那么会拒绝。如果ld或candidate发现自己的任期更小了,那么会立刻转变为follower
    7. 时序:client request -> ld -> 将log entry复制到半数以上服务器,并得到回复 -> ld commited、apply -> 返回响应给client ->后面心跳检测(AE)时,随便告诉其他服务器自己已经commited并apply
  2. Leader election

    1. 当election timer计时结束,还没有ld发请求,那么follower会认为ld死了,会变成candicate,发起选举
    2. 如果split votes发生了,那么term会增加,并再次发起选举
    3. timer计时器,是随机的
    4. 注意:每一个新ld的产生,由于它要获得多数server的认可,在请求投票时会把最新的term同步给多数的server!因此term也是一个“多数共识”的标识。
  3. Log replication

    1. 当ld 接收到log entry时,它会保证大多数server都接受到这个log entry,才会继续自己的下一步操作(如返回响应给client)
    2. 如果一个server对接受log entry没有响应,ld会无限地尝试
    3. 如果ld认为LE(log entry)是足够安全的了,那么这个时候叫作committed;注意,apply和committed是不一样的
    4. 在之后,ld会通过AE来将已经committed的index告知给各个follower
    5. 当ld发送AE给follower时,如果follower发现日志冲突,那么ld会decrements nextIndex,直到两者保持一致。注意:ld永远不会重写/删除自己的日志。(decrements nextIndex,不会把follower上的日志删除吗?会的,但是ld一定有了所有能被commited的日志,因此以ld为准。)
  4. Safety

    1. raft保证,被选举出的ld,一定会存有所有已经commited的日志(这个最难理解了。没有commited的entry又怎么处理呢?这样理解,要想commited,那么日志一定是被复制到“半数以上的服务器”。而新ld一定是“半数以上的服务器”中的一个。因此,只要是新ld,那么一定有能保证被commited的日志 。)。:the voter denies its vote if its own log is more up-to-date than that of the candidate。也就是说,要被投票的candidate的日志,要比半数以上的voter的日志要more up-to-date。(什么叫more up-to-date?更大term;如果term相同,则更大index)

      leader的前提是majority,因此leader肯定拥有majority的log(这就是为什么叫做共识)

      上面说法有问题:更正一下:raft保证,被选举出的ld,一定会存有比大多数server更up-to-date的日志

      leader的前提是majority都同意,因此leader肯定拥有majority都同意的更up-to-date的log(这就是为什么叫做共识)

      总结一下:大多数server都认为A服务器有比自己more up-tp-date的log**(共识)**,那么A就可以是ld。

    2. ld只允许commited自己任期内的日志?为什么:

      1. 新ld上线时,不能够确定旧的entry是否已经被commited(如重启后,commitedIndex被重置),旧的entry是否已经被大多数server所有。

        当能commite自己任期内的log entry时,就已经说明前面任期的所有日志一定已经复制到大多数server了。

        因此,只能通过提交自己任期内的log entry,来间接说明之前的日志可以提交。

        同时,能commited自己任期内的日志,说明已经通知到了半数以上服务器,这个时候,半数以上的服务器的日志中的term是和ld一样是最新的。

      2. 图8,描述了,log即使存储在大多数的server上,仍然可能被后面的新ld覆盖(图8的d)。

        因此不能够直接通过复制的数量来判断之前任期的日志条目是否提交(图8的c)。

        所以才出现下下面的解决方案:ld只允许提交自己任期内的log entry。这样保证,当 图8的e 的S1的任期4日志被提交时,任期为3的自然也算被提交了。

  5. Timing and availability:broadcastTimeelectionTimeoutMTBF(平均故障时间)

    1. broadcastTimeelectionTimeout ,如果不能保证这个,那么会频繁出现选举失败
    2. electionTimeoutMTBF,保证这个是因为,让选举平稳进行。这个用脑子想想就知道~,为了保证系统平衡运行,肯定这种定时器要小于故障时间的。
  6. Cluster membership changes

    1. 使用了joint consensus,两阶段转变。首先转为joint状态(中间态),然后再转变为new configuration状态
    2. raft的实现中,在中间态依然可以正常进行选举和处理client的请求
  7. Log compaction

    1. 使用了快照。这个好像在lab3用得到。
  8. Client interaction

    1. 初始时,client会随机挑选一个server进行连接
    2. client发送的请求,都会带有一个 唯一的id
    3. 如果重复请求,那么server会通过请求的id,直接返回之前已经执行过的请求的响应

文章的假设:

  • 应用程序状态是易失的
  • 当一个机器死掉后,通过心跳确认自己的apply位置,并重演一次操作(先不考虑日志压缩)

问题:

  1. 如何避免脑裂?

    1. majority voting system。这个是整个机制的基石
    2. odd servers
    3. 当出现网络partition时,绝不可能有超过一边拥有一半以上的服务器
    4. 大多数投票机制保证:在每一步要投票时,保证投票的“大多数”机器中,一定有一部分会和上次投票重叠。
  2. 如何知道“半数以上”?

    1. raft算法中,每个服务器(节点)都会保存一些关于集群的信息,其中就包括集群的总数目(server count)。这个信息可以在集群初始化的时候,由配置文件或者命令行参数来指定,也可以在集群运行的过程中,由领导者节点来动态更新。
    2. 总数目是固定的,不会因为机器的故障而减少!!!
  3. 要是因网络故障,完全将raft的服务器分区成两半,怎么办?

    1. 绝不可能有超过一边拥有一半以上的服务器
  4. Raft集群最大能忍受的故障server数目是多少?

    1. 假设一共有2f + 1台机器,那么最多允许f台机器故障。底层原理是因为投票机制是多数机制
    2. 如果是有n台机器,那么就是 2f+1=n,f = (n - 1) / 2
  5. 有不确定性操作的命令怎么办?

  6. 为什么需要log entry?

    1. 为了保证操作顺序
    2. 暂存操作。因为操作到来不确定是否一被要执行。
    3. 保存副本,当网络故障时,可以重发给follower
  7. Raft为什么需要要ld?(比如Paxos就没有ld)

    1. 加速系统应答
    2. 让系统更加容易理解
  8. 如果因为网络故障分裂成两个partition,旧ld在一半,但另一半有超过半数的server并且选举出了新ld,这个时候如何处理?为什么旧ld不会导致错误发生?

    1. 因为旧ld不会得到多数server的回应,因此不会成功执行任何命令
  9. 如果一个server的term跑得太快怎么办?

    1. 快就快。有投票机制的保证,没有关系的。
  10. 那么这些entry在旧ld执行后返回给client时失败了怎么办?新上任的ld还会再执行再给返回client吗?

    1. 请求是有带id的,可以通过id来寻找已经执行的结果。
  11. 如果一个ld已经把log复制给大多数server了,但是在commited之前挂掉了。那么这个log算是commited吗?

    1. 还是Figure8©。不算的。只有当前ld将自己任期内的log提交了,之前的所有log才算是commited!
  12. 不能够通过“已经复制日志给大多数server”,来判断“是否已经commited”

    1. 还是Figure8©
  13. 为什么不选有最长日志的,作为领导人?

    1. 最长不代表最up-to-date 。最长不代表能复制给多数server。也就是没有共识。
  14. 什么是线性化语义?

    在Raft协议中,“linearizable semantics”(线性化语义)是一个重要的概念。这意味着,对于任何两个操作,如果在实际执行中,操作A在操作B之前完成,那么在系统的状态中,操作A就应该在操作B之前

    在Raft协议中,为了实现线性化语义,通常会在服务器端维护一个关于已经执行过的请求的记录。这个记录通常包括每个客户端的最后一个请求的ID以及对应的响应。当收到一个新的请求时,服务器首先会检查这个请求的ID是否已经存在于记录中。如果存在,说明这个请求是重复的,服务器就会直接返回之前的响应,而不会再次执行这个请求

    总的来说,"linearizable semantics"是Raft协议中保证一致性的重要机制,它能够确保所有的操作都能按照一定的顺序执行,并且每个操作只执行一次

LEC5、6:Raft

随便记记:

  • mapReduce、GFS、VM-FT都单一实体来决定谁是ld
  • 最详细对raft的资料:https://raft.github.io/
  • 教学动画:https://thesecretlivesofdata.com/raft/

LAB2

注意点:

  1. Raft will continue to operate as long as at least a majority of the servers are alive and can talk to each other. If there is no such majority, Raft will make no progress, but will pick up where it left off as soon as a majority can communicate again.
  2. the service expects your implementation to send an ApplyMsg for each newly committed log entry to the applyCh channel argument to Make()
  3. Your Raft peers should exchange RPCs using the labrpc Go package (source in src/labrpc).:因为测试器会模拟丢包等网络故障
2A

http://nil.csail.mit.edu/6.824/2020/labs/lab-raft.html

task
  1. 实现ld选举 及 心跳检测。当旧ld死掉时(当follower收不到旧ld的心跳时),要有接管机制
Hint
  1. 只关注你当前的任务(但是应该也要考虑到后面的扩展)
  2. 本实验中:the number of Raft peers (usually 3 or 5)
  3. Add the Figure 2 state for leader election to the Raft struct in raft.go.
  4. Modify Make() to create a background goroutine that will kick off leader election periodically by sending out RequestVote RPCs when it hasn’t heard from another peer for a while. This way a peer will learn who is the leader, if there is already a leader, or become the leader itself. Implement the RequestVote() RPC handler so that servers will vote for one another. 就是要有一个机制,心跳超时后要发起选举。
  5. The tester requires that the leader send heartbeat RPCs no more than ten times per second.每秒不得多于10次的心跳检测
  6. 旧ld死掉后,要求5秒内就要完成新ld的选举。因为要求选举时间和心跳间隔选得尽可能短
  7. The paper’s Section 5.2 mentions election timeouts in the range of 150 to 300 milliseconds. Such a range only makes sense if the leader sends heartbeats considerably more often than once per 150 milliseconds. Because the tester limits you to 10 heartbeats per second, you will have to use an election timeout larger than the paper’s 150 to 300 milliseconds, but not too large, because then you may fail to elect a leader within five seconds.(?) 总的来说,这个是说election timer的时间,应该设置超过150~300 milSecond。(gpt建议300到500)。但是不知道原理。。
  8. 使用loop+time.Sleep()来完成周期性任务
  9. You may find this guide useful, as well as this advice about locking and structure for concurrency.
  10. The tester calls your Raft’s rf.Kill() when it is permanently shutting down an instance. You can check whether Kill() has been called using rf.killed(). You may want to do this in all loops, to avoid having dead Raft instances print confusing messages. 就是test发送信号要永久杀死一个server,但是不是通过进程强制杀死。要处理这个信号。周期性任务要通过这个标志判断,是否要继续。
  11. debug:
    1. 可以用print语句,然后使用 go test -run 2A > out. 查看
    2. You might find DPrintf in util.go useful to turn printing on and off as you debug different problems.
  12. 要通过RPC发送的字段,必须大写
  13. 使用go test -race,来保证代码没有race
  14. 测试时间限制: For all of labs 2, 3, and 4, the grading script will fail your solution if it takes more than 600 seconds for all of the tests (go test), or if any individual test takes more than 120 seconds.
locking
  1. 不论读写,如果要保证一致性的,一定要加锁
  2. Code that waits should first release locks. If that’s not convenient, sometimes it’s useful to create a separate goroutine to do the wait.
  3. 等待的代码,要释放锁。但是等待的代码执行完毕后,要重新获得锁,并判断自己的assumption是否还和当前的环境相同(将当时主线程的参数复制到goroutine中)。
structure
  1. 长时间运行的 activities ,应该在不同的线程运行。不同activities 应该也要分割开
  2. 处理timeout的通用思路:存储一个最后时间a,睡眠,然后在某个时间b,判断 b - a > timeout?
  3. 在将log送入到applych时,必须保证顺序。因此这个操作只能在一个goroutine执行
  4. 推进 commitIndex 的代码需要触发应用 Goroutine。为了实现这一点,建议使用条件变量(如 Go 中的 sync.Cond):就是signal机制。
  5. 每个RPC的发送和处理,应该在同一个goroutine.
guide
  1. figure2是绝对权威的总指导

  2. hearbeat返回时,如果返回true,是隐式地告诉ld,当前follower的日志和ld完全同步。因此即使是hearbeat,也要检测里面的term等状态。

  3. 什么时候重置election timer?

    1. 从当前ld接受到AE
    2. 自己开始一个选举期
    3. 投票给其他peer的时候。
  4. 一个任期内,只能投票一次!但是由于这个规则的存在:If RPC request or response contains term T > currentTerm: set currentTerm = T, convert to follower。这会改变当前follower的term,因此可以再次投票

  5. Check 2 for the AppendEntries RPC handler should be executed even if the leader didn’t send any entries. 也就是说,heartbeat应该同正常的AE同等对待。

  6. nextIndex 和matchIndex的不同:

    1. nextIndex:是极其乐观的,初始化为 index+1。ld用来指导FO从哪里开始复制日志
    2. matchIndex:是保守、安全的,初始化为-1。用来指示FO已经复制的最高索引。只有在FO对AE请求返回true时,这个matchIndex才更新。
  7. 对于过期响应的怎么处理:应该在args的参数中保留你发送时的term,然后在返回响应时,比较当前term和当前发送的term是否一样。如果不一样,直接丢了。

  8. matchIndex的更新:如果在收到响应后,已经check过assumption了,那么应该将matchIndex=prevLogIndex+len(entrites[]),而不是直接 matchIndex=nextIndex-1 or matchIndex = len(log)。因为在发送请求的期间,nextIndex可能已经改变了(比如故障重启),len(log)更会改变,比如有Client请求拼接。

  9. 快速恢复的nextIndex:https://thesquareplanet.com/blog/students-guide-to-raft/#an-aside-on-optimizations

    在AE的reply时,返回多两个字段:conflictIndex和conflitTerm

    1. 如果FO没有prevLogIndex的日志,那么直接返回 conflictIndex=len(FO自己的所有log), conflictTerm=None
    2. 如果FO有prevLogIndex的日志,但是term不匹配(设FO的冲突的Term为termA)。则返回 conflictTerm=log[prevLogIndex].Term=termA。并把 conflictIndex设置为termA的第一个log
    3. 当LD收到冲突响应时,首先查找自己是否有 conflictTerm=termA的日志。如果有,将nextIndex设置为termaA的最后一个日志的下一个位置。
    4. 如果没有termA的日志,则直接将nextIndex=conflictIndex

    简单折中实现就是只用conflictIndex不用conflictTerm,但这样在某些情况下会多发送些log entry。

    conflictIndex的作用:

    • 跳过所有FO自己没有的日志
    • 跳过一个term的日志(这里就是把所有冲突的termA全部跳过)

    conflitTerm的作用:

    • 辅助,让 LD 的nextIndex不要把所有的termA日志都跳过
  10. If the leader has no new entries to send to a particular peer, the AppendEntries RPC contains no entries, and is considered a heartbeat. 也就是说,同步日志的频率至少和hearbeat一样!或者说,直接把同步日志这个功能做成heartbeat。如果有需要同步的日志,那么直接同步。如果没有需要同步的日志,则看成是一个heartBeat(entries=null)。

    遇到的问题:在hearbeat实现的时候,没有按AE的规则来严格设置prevLogIndex和相应的entries[],导致一些bug出现。比如一个hearbeat过来,带了最新的leadercommit,把FO的rf.commit更新了,但hearbeat并没有携带最新的log。

    因此,在实现的时候,直接把同步日志做成心跳检测。逻辑上统一了。并设置条件变量,在需要的时候手动触发一次同步日志。(也就是设置死循环,用和heartBeat一样的频率触发这个条件变量。然后这个条件变量也可以在其他地方手动触发)

    所以是把 AE看成是hearbeat… 有点奇怪的感觉

设计与编码

有哪些周期性activity:

  1. ld的心跳检测
  2. FO的election timeout

要加哪些额外的状态?

  1. 当前ld的id

动作有哪些?

  1. ld发送心跳
  2. FO变成CA,并发起选举,请求多数投票
  • 被killed()了,那么剩下的已经启动的goRoutine怎么办?难道说每一个动作后面都要加killed()判断?,那也太麻烦了吧。目前看来,只要在各个函数头加上killed()判断就行,即使剩下的go routine被执行了,也不会造成实质性的伤害。 然后每一个动作后加上killed()判断,更直观点,毕竟killed()也是assumption之一。
  • 注意:rf.dead变量虽然是原子的,但这种原子性是为了保护这个变量。所以判断killed()的时候,最好也当成关键性代码,用mutex包裹起来。
  • 小心!defer如果放在一个死循环里面,会执行不了!
2B
task

Implement the leader and follower code to append new log entries, so that the go test -run 2B tests pass.

Hint
  1. 实现Start()函数拼接日志,并同步
  2. One way to fail to reach agreement in the early Lab 2B tests is to hold repeated elections even though the leader is alive. Look for bugs in election timer management, or not sending out heartbeats immediately after winning an election
设计与编码
  1. 当service调用Start()时,拼接日志到log[],signal条件变量cond1
  2. 当ld的 last log index >= nextIndex时,要发送同步日志 syncLogToPeer。成功则更新nextIndex和matchIndex。失败的话,减少nextIndex,继续尝试,signal一下条件变量cond1。然后刚成为LD的时候,应该也要启动一下这个。
  3. 如何确认能commited?当 N > commitIndex,并且N大于大多数的matchIndex,并且log[N].term == rf.currentTerm,那么就能commit到这里。什么时候检查?先定期吧,简单点。
2C
task
  1. Complete the functions persist() and readPersist()
  2. Insert calls to persist() at the points where your implementation changes persistent state
Hint
  1. You will probably need the optimization that backs up nextIndex by more than one entry at a time
question

实现中疑惑的点:

  • 同步日志的时候,如果用条件变量来实现,那么当一个server crash的时候,没有时机去触发这个条件变量。后面我还是用了for+sleep来实现。有什么好的办法?
  • 条件变量的用处似乎不大?因为都是周期性任务。而且如果用触发来做,有些情况又触发不了。不过实现的时候,apply log用了条件变量。这个是一定可以被触发的。
  • 代码中还有比较多的todo偷懒没搞hh,那些都是可以优化的点
后记

全部代码写完后,重新运行三个test。均通过。

由于1次实验有偶然性,再运行10次 go test -run 2,也均通过。(要多运行几次,小概率的bug才会出现)

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

  1. 写代码前,还是得弄清楚需求(这里是看大量lab相关的文档)。写代码加调试花了2~3天(周日下午到周三早上,期间还帮师兄改了论文),但看论文和文档远远不止。

  2. 写完后,看了别人的代码,差别还是挺大的hh,自己实现得比较乱,别人可以这么优雅

  3. 而且要遵守建议和论文中的规则,自己创造性地“乱写”(没有被证明对),那么debug之路会很漫长

  4. RPC调用与assumption

  5. 日志索引从1开始,确实很妙,省去了非常多的代码判断。

LEC5:GO, Threads, and Raft

  1. 在写实验的时候,用大粒度锁就行,别trick.去想着从cpu层面优化~
  2. The Go Memory Model:If you must read the rest of this document to understand the behavior of your program, you are being too clever. Don’t be clever.
  3. 如果你的代码中出现了常数,要想想为什么可以是常数?为什么是这个常数,其他常数不行?
go threads技巧

waitGroup、闭包(能访问到创建该线程的上下文)

//1.可以作为投票的一种实现
func main() {var wg sync.WaitGroupfor i := 0; i < 5; i++ {wg.Add(1)go func(x int) {sendRPC(x)wg.Done()}(i) //2.i要传递}wg.Wait()
}func sendRPC(i int) {println(i)
}

周期性任务

func periodic() {for {println("tick")time.Sleep(1 * time.Second)mu.Lock() //如果不加锁,无法保证能马上见到其他人作的改变if done {return}mu.Unlock()}
}

条件变量 (signal):建议实验中直接用broadcast

func main() {rand.Seed(time.Now().UnixNano())count := 0finished := 0var mu sync.Mutexcond := sync.NewCond(&mu)for i := 0; i < 10; i++ {go func() {vote := requestVote()mu.Lock()defer mu.Unlock()if vote {count++}finished++cond.Broadcast()}()}mu.Lock() //注意。要先获得lock才能wait。相当于java中,synchorized 这个功能放进了Object中了for count < 5 && finished != 10 {cond.Wait()}if count >= 5 {println("received 5+ votes!")} else {println("lost")}mu.Unlock()
}func requestVote() bool {time.Sleep(time.Duration(rand.Intn(100)) * time.Millisecond)return rand.Int() % 2 == 0
}
mu.Lock()
// do something that might affect the condition
cond.Broadcast()
mu.Unlock()----mu.Lock()
while condition == false {cond.Wait()
}
// now condition is true, and we have the lock
mu.Unlock()

channel(无缓冲channel):

  • 是一种没有容量的队列。当发送时,如果没有接收方,发送线程会被阻塞。相反地,如果没有人发送,接收方也会被阻塞
  • 可用于生产者消费者
  • waitGroup效果
func main() {done := make(chan bool)for i := 0; i < 5; i++ {go func(x int) {sendRPC(x)done <- true}(i)}//和waitGroup的效果一样for i := 0; i < 5; i++ {<-done}
}func sendRPC(i int) {println(i)
}
raft实验易错点
  1. 不应该在调用RPC时,持有锁。1影响效率,2容易死锁。可以通过传递assumption消除
debug技巧
  1. cirt + /,可以打印堆栈

这篇关于MIT-6.824-Lab2,Raft部分笔记|Use Go的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/738964

相关文章

Go信号处理如何优雅地关闭你的应用

《Go信号处理如何优雅地关闭你的应用》Go中的优雅关闭机制使得在应用程序接收到终止信号时,能够进行平滑的资源清理,通过使用context来管理goroutine的生命周期,结合signal... 目录1. 什么是信号处理?2. 如何优雅地关闭 Go 应用?3. 代码实现3.1 基本的信号捕获和优雅关闭3.2

【学习笔记】 陈强-机器学习-Python-Ch15 人工神经网络(1)sklearn

系列文章目录 监督学习:参数方法 【学习笔记】 陈强-机器学习-Python-Ch4 线性回归 【学习笔记】 陈强-机器学习-Python-Ch5 逻辑回归 【课后题练习】 陈强-机器学习-Python-Ch5 逻辑回归(SAheart.csv) 【学习笔记】 陈强-机器学习-Python-Ch6 多项逻辑回归 【学习笔记 及 课后题练习】 陈强-机器学习-Python-Ch7 判别分析 【学

系统架构师考试学习笔记第三篇——架构设计高级知识(20)通信系统架构设计理论与实践

本章知识考点:         第20课时主要学习通信系统架构设计的理论和工作中的实践。根据新版考试大纲,本课时知识点会涉及案例分析题(25分),而在历年考试中,案例题对该部分内容的考查并不多,虽在综合知识选择题目中经常考查,但分值也不高。本课时内容侧重于对知识点的记忆和理解,按照以往的出题规律,通信系统架构设计基础知识点多来源于教材内的基础网络设备、网络架构和教材外最新时事热点技术。本课时知识

poj 2976 分数规划二分贪心(部分对总体的贡献度) poj 3111

poj 2976: 题意: 在n场考试中,每场考试共有b题,答对的题目有a题。 允许去掉k场考试,求能达到的最高正确率是多少。 解析: 假设已知准确率为x,则每场考试对于准确率的贡献值为: a - b * x,将贡献值大的排序排在前面舍弃掉后k个。 然后二分x就行了。 代码: #include <iostream>#include <cstdio>#incl

Go Playground 在线编程环境

For all examples in this and the next chapter, we will use Go Playground. Go Playground represents a web service that can run programs written in Go. It can be opened in a web browser using the follow

论文阅读笔记: Segment Anything

文章目录 Segment Anything摘要引言任务模型数据引擎数据集负责任的人工智能 Segment Anything Model图像编码器提示编码器mask解码器解决歧义损失和训练 Segment Anything 论文地址: https://arxiv.org/abs/2304.02643 代码地址:https://github.com/facebookresear

go基础知识归纳总结

无缓冲的 channel 和有缓冲的 channel 的区别? 在 Go 语言中,channel 是用来在 goroutines 之间传递数据的主要机制。它们有两种类型:无缓冲的 channel 和有缓冲的 channel。 无缓冲的 channel 行为:无缓冲的 channel 是一种同步的通信方式,发送和接收必须同时发生。如果一个 goroutine 试图通过无缓冲 channel

数学建模笔记—— 非线性规划

数学建模笔记—— 非线性规划 非线性规划1. 模型原理1.1 非线性规划的标准型1.2 非线性规划求解的Matlab函数 2. 典型例题3. matlab代码求解3.1 例1 一个简单示例3.2 例2 选址问题1. 第一问 线性规划2. 第二问 非线性规划 非线性规划 非线性规划是一种求解目标函数或约束条件中有一个或几个非线性函数的最优化问题的方法。运筹学的一个重要分支。2

【C++学习笔记 20】C++中的智能指针

智能指针的功能 在上一篇笔记提到了在栈和堆上创建变量的区别,使用new关键字创建变量时,需要搭配delete关键字销毁变量。而智能指针的作用就是调用new分配内存时,不必自己去调用delete,甚至不用调用new。 智能指针实际上就是对原始指针的包装。 unique_ptr 最简单的智能指针,是一种作用域指针,意思是当指针超出该作用域时,会自动调用delete。它名为unique的原因是这个

如何确定 Go 语言中 HTTP 连接池的最佳参数?

确定 Go 语言中 HTTP 连接池的最佳参数可以通过以下几种方式: 一、分析应用场景和需求 并发请求量: 确定应用程序在特定时间段内可能同时发起的 HTTP 请求数量。如果并发请求量很高,需要设置较大的连接池参数以满足需求。例如,对于一个高并发的 Web 服务,可能同时有数百个请求在处理,此时需要较大的连接池大小。可以通过压力测试工具模拟高并发场景,观察系统在不同并发请求下的性能表现,从而