精华内容
下载资源
问答
  • 的英语单词
    万次阅读
    2014-09-29 17:55:13

    abide v.(by)坚持,遵守
    about ad. 在周围,附近,到处;大约,差不多 prep. 关于,对于;在……周围,在……附近 a.准备
    above prep. 在……上面,超过,高于a. 上面的,上述的ad. 在上面,以上
    abuse v./n. 滥用;虐待;谩骂
    actor n. 男演员
    acute a. 敏锐的,尖锐的;(疾病)急性的
    adapt v.(to)(使)适应,适合;改编,改写
    admit vt.承认,供认;准许…进入,准许...加入
    adopt v. 采用,采纳,通过;收养
    adore v.崇拜,爱慕,(口语)喜爱
    adult n. 成(年)人 a. 成年人的,已成熟的
    after prep. 在……以后,在……后面 conj. 在……后 ad. 以后,后来
    again ad. 又,再(次),重新
    agent n. 代理商(人),代表
    agony n. 苦恼,痛苦
    agree v.(to, with)同意,赞成;一致,适合
    ahead ad. 在前,向前,提前,前头
    aisle n.走廊,过道
    alarm n. 警报;惊恐,惊慌 v. 使惊恐,惊动,惊吓;向……报警
    album n.集邮本,照相簿
    alert a. 警惕的;机灵的 n.警惕,警报 vt.(常与to连用)警告
    alien n. 外侨;外星人a. 外国的;(from)相异的;(to)不相容的
    alike a. 相同的,相像的
    alive a. 活着的;活跃的,热闹的
    allow   v. 允许,准许;承认;让……得到
    alloy n. 合金
    alone a. 单独,独自,独一无二的 ad. 仅仅,只;单独地,独自
    along prep. 沿着ad. 向前
    aloud ad. 出声地,大声地
    alter v. 改变,变更
    amaze v. 使惊奇,使惊愕,使惊叹
    amend v. 修改,修正
    among prep. 在……之中,在……中间
    ample a. 充分的,富裕的;宽敞的,宽大的
    amuse v. 逗……笑,给……以娱乐(消遣)
    angel n. 天使
    anger n.(愤)怒,气愤v. 使发怒,激怒
    angle n. 角;角度,方面,观点
    angry a. 愤怒的;生气的;(风雨等)狂暴的
    ankle n. 踝
    annoy v. 使烦恼,使生气,打搅
    apart ad. 撇开;分开,分离;相距,相隔,除去
    appal vt.使胆寒,使惊骇
    apple n. 苹果(树)
    apply v.(for)申请,请求;(to)适用,应用,运用
    April   n. 四月
    argue v. 争论,辩论;主张,论证;说服
    arise v. 出现,发生;(from)由……引起,由……产生
    array n. 一系列,大量;排列v. 排列
    arrow n. 箭;箭头(符号),箭状物
    aside ad. 在旁边,到旁边
    asset n.资产,有用的东西
    audio a.音频的,声频的,声音的
    audit n.审计,稽核,查帐 vt.稽核,旁听 vi.查账
    aural a. 听觉的
    avail n. [一般用于否定句或疑问句中]效用,利益,帮助 v. 有用于,有助于
    avert v. 防止,避免;转移(目光、注意力等)
    avoid v. 避免,回避,逃避
    await v. 等候,期待
    awake a. 醒着的,警觉的 v. 唤醒,唤起;觉醒,醒悟到,认识到
    award n. 奖(品) v. 授予,奖给
    aware a.(of)知道的,意识到的
    awful a. 极度的,极坏的,糟糕的;威严的,可怕的 ad. 十分,极度地
    bacon n. 咸肉,熏肉
    badge n. 徽章
    badly ad. 坏,恶劣地;严重地,非常,厉害
    basic a. 基本的,基础的
    basin n. 盆,脸盆;内海,盆地
    basis n. 基础,根据
    batch n. 一批,一组,一群
    bathe v. 游泳,洗澡,浸,洗,弄湿
    beach n. 海滩,湖滩,河滩
    beard n. 胡须
    beast n. 兽,牲畜;凶残的人,举止粗鲁的人
    begin v. 开始
    being n. 生物,人;存在,生存
    belly n.腹部,胃 vi.涨满
    below prep. 在……下面,在……以下 ad. 在下面,向下
    bench n. 长凳,条凳;(工作)台,座
    Bible   n.《圣经》
    birth n. 出生,分娩;出身,血统
    black a. 黑(色)的,黑暗的 n. 黑人,黑色
    blade n.刀刃,刀片
    blame v. 责备;怪,怨,把……归咎于 n. 责任,过错;责备
    blank a. 空白的,空着的;失色的,无表情的 n. 空白,表格
    blast n. 一阵(风),一股(气流);爆炸冲击波;管乐器或汽车笛声 v. 爆炸,爆破
    blaze n. 火焰;火光;闪光,光辉 v. 燃烧,冒火焰
    bleak a. 荒凉的;冷酷的;没有希望的
    bleed v. 出血,流血
    blend n. 混合(物)v. 混合,混杂
    bless v. 祝福,保佑
    blind a. 瞎的;盲目的 v. 使失明;蒙蔽 n. 百叶窗
    block n. 大块木料(或石料、金属);一排房屋,街区;阻塞 v. 阻塞,拦阻,封锁
    blood n. 血(液);血统,宗族,门第;血气,气质
    bloom n. 花(朵);开花(期)v. 开花
    blunt   a. 率直的;钝的 n.(使)钝;(使)迟钝
    blush n./v. 脸红
    board n. 板,木板,纸板;全体委员,委员会,部门;伙食;船舷 v. 上船(车,飞机等)
    boast v.(of, about)自夸,夸耀 n. 自夸,大话
    bonus n. 奖金,红利
    boost v.推进
    booth n. 电话亭,货摊
    bosom n.(心)胸
    bound v./n. 跳(跃) a. 被束缚的,理应……的,一定的;准备(或正在)到……去的,开往……的
    bowel n.肠 a.内部,同情心
    brace v. 使防备,使受锻炼;支撑;使(手、足、肩等)绷紧 n. 托架,支架
    brain n.(大)脑,骨髓;[pl.]脑力,智能
    brake v./n. 制动(器),闸,刹车
    brand n. 商标,标记,牌子 v. 使铭记;打火印,打烙印
    brass n. 黄铜,铜器
    brave a. 勇敢的
    bread n. 面包
    break v. 打破,折断,破碎;使中止,打断;破坏,违反 n. 打断,中止;休息时间
    breed v.(使)繁殖,生殖;产生,引起;教养,抚养,饲养 n. 品种,种类
    bribe n. 贿赂 v. 向……行贿,买通
    brick n. 砖(状)物
    bride n. 新娘
    brief a. 简短的,简洁的 v. 简短介绍,简要汇报
    bring v. 带来,拿来;引起,导致
    brisk a. 轻快的;生气勃勃的;兴隆的
    broad a. 宽的,广阔的;广大的,广泛的;宽宏的,豁达的
    brook n. 小河,溪
    broom n. 扫帚
    brown n./a. 褐色(的),棕色(的)
    brush n. 刷(子),毛刷;画笔v. 刷,擦,掸,拂;擦过,掠过
    build v. 造,建筑,建设,建立
    bully n.欺凌弱小者 vt.威吓,威逼
    bunch n.(一)簇,束,捆,串
    burst v. 爆裂,炸破;突然发生,突然发作 n. 突然破裂,爆发
    cabin n. 客舱,机舱;小(木)屋
    cable n. 电报;电缆;缆,索,钢丝绳v. 拍电报
    camel n. 骆驼
    canal n. 运河;(沟)渠
    candy n. 糖果
    canoe n. 独木舟,小游艇
    cargo n. 船货,货物
    carry v. 运送,搬运;传送,传播;领,带
    carve v.(雕)刻
    catch v. 捕捉,捕获;赶上;感染;理解,听到
    cater vi.(for/to)满足,迎合;(for)提供饮食及服务
    cause n. 原因,理由;事业,事件,奋斗目标 v. 使产生,引起
    cease v./n. 停止,中止
    chain n. 链(条);[pl.]镣铐;一连串,一系列,连锁 v. 用链条拴住
    chair n. 椅子;主席(席位)
    chalk n. 粉笔,白垩
    chaos n. 混乱,紊乱
    charm n. 吸引力;美貌 v. 迷人,(使)陶醉;施魔法于
    chart n. 图,图表
    chase v./n. 追逐,追求
    cheap a. 便宜的;低劣的,不值钱的
    cheat v. 欺骗;作弊 n. 骗子;欺诈,欺骗行为
    check v. 检查,核对;制止;(凭票)托运或寄存 n.(=cheque)检查,核对;方格图案 n. 支票
    cheek n. 面颊,脸
    cheer v.(使)振奋,(使)高兴v./n. 喝彩,欢呼
    chess n. 棋
    chest n. 胸腔,胸膛;箱,柜
    chief a. 主要的,首要的 n. 首领,领袖
    child n.( [pl.] children)小孩,儿童,儿女
    chill n. 寒冷,寒气,寒战 v. 使寒冷
    china   n. 瓷器
    choke n. 窒息,噎住;闷塞,堵塞,阻塞
    cigar n. 雪茄烟
    civil a. 公民的,市民的;国内的,民间的;民用的;有礼貌的,文明的;文职的
    claim v. 要求;声称,主张;索赔 n. 要求;主张,断言;索赔;权利,要求权,所有权
    clash v./n. 碰撞 n. 碰撞声
    clasp n. 扣子,钩子;握手,拥抱 v. 扣住,钩住;紧握,紧抱
    class n.班级,年级;(一节)课;阶级,阶层;等级,类别 v. 把……分类(或分等)
    clean a. 清洁的,干净;洁白的 v. 打扫,使干净
    clear a. 清晰的;晴朗的;清澈的;畅通的,无阻的 ad. 清楚地,清晰地,明白地 v. 澄清,清除,扫清;使清楚
    clerk n. 职员,办事员;店员
    click v.发出滴答声 n.滴答声
    cliff n. 悬崖;峭壁
    climb v./n. 攀登,爬
    cling v.(to)粘住;依附;坚持
    cloak n. 外套,斗篷 v. 掩盖,掩饰
    clock n. 钟
    clone n./v.克隆,无性繁殖,复制
    close v.闭;结束 n. 结束,了结 a.(to)近的;关闭着的;秘密的;严密的,紧密的 ad. 接近地
    cloth n.(一块)布,织物,衣料
    cloud n. 云(状物);遮暗物,阴影;一大群
    coach n.(铁路)客车,长途汽车,大客车;辅导员,教练,私人教师 v. 教练,辅导,指导
    coast n. 海岸,海滨
    color n.(=colour)颜色;颜料;肤色 v.给…着色 9
    comic n.滑稽演员 a.滑稽的,喜剧的
    couch n. 睡椅,长沙发椅
    cough v./n. 咳嗽
    could aux. v. can的过去式;[用于语气婉转的请求]能;[用于虚拟语气]能,可以
    count v. 数,计算;算入;看作,认为 n. 计数,计算,总数
    court n. 法院,法庭;宫廷,朝廷;院子;球场
    cover v. 覆盖,遮蔽,包括,涉及 n. 盖子,套子;(书的)封面
    crack n. 裂纹,裂缝,缝隙;破裂声,爆裂声 v.(使)破裂,砸开;(使)发出爆裂声
    craft n. 工艺,手艺,技巧;飞机,飞船
    crane n. 起重机;鹤
    crash v./n. 碰撞,坠落,摔坏 n. 失败,瓦解;撞击声,爆裂声
    crawl v./n. 爬行,蠕动;缓慢(的)行进
    crazy a. 疯狂的,古怪的,蠢的;(about)狂热的,热衷的
    cream n. 乳脂,(鲜)奶油;奶油色
    creep v. 爬,爬行;(植物)蔓延
    crime n. 罪行,犯罪
    crisp a. 脆的,易碎的
    cross n. 十字形,十字架 a. 交叉的,横穿的;易怒的,发怒的 v. 越过,穿过;(使)交叉,(使)相交
    crowd n. 人群;一群,一伙 v. 聚集,群集;挤满,拥挤
    crown n. 王冠,冕;君权,君王 v. 为……加冕
    crude a. 天然的,未加工的;生的,未熟的;粗鲁的,粗野的
    cruel a. 残忍的,残酷的
    crush n./v. 压碎,压坏 v. 压服,压垮
    crust n. 外皮,壳;地壳
    curse v./n. 诅咒,咒骂
    curve n. 曲线,弯曲(物) v. 弄弯,成曲形
    cycle n. 自行车;周期,循环 v. 骑自行车;循环
    daily a. 每日的 ad. 每日,天天 n. 日报
    dance v. 跳舞,舞会
    datum n.数据,资料
    death n. 死亡;灭亡,毁灭
    eight num. 八,八个
    dairy n. 牛奶场,奶店
    enjoy v. 欣赏,喜爱;享受……乐趣
    erupt v.(尤指火山)爆发
    erase v. 擦掉;删去
    draft n. 草稿,草案,草图 v. 起草,草拟
    elbow n. 肘,弯头 v. 用肘挤
    depth n. 深度,深奥,深刻
    dozen n. 一打,十二个
    exile n.放逐,流放,流犯,被放逐者 vt.放逐,流放
    decay v./n. 腐朽,腐烂;衰减,衰退
    extra a. 额外的,附加的 n. 附加物,额外的东西
    ditch n. 沟,渠,水沟
    drain n. 排水沟,阴沟;消耗,负担 v. 排去,放干
    evoke vt.唤起,引起,博得
    enter v. 走进,参加,加入
    exert v. 尽(力),施加(压力等)
    elite n. [总称]上层人士,掌权人物,实力集团;出类拔萃的人(集团),精英
    endow v.捐赠,赋予
    enemy n. 敌人,敌军
    empty a. 空的;空洞的 v. 倒空,使成为空的
    dread v./n. 恐惧,担心
    dream n./v. 梦,梦想,幻想
    drunk a. 酒醉的
    dense a. 浓厚的,密集的,稠密的
    drift v./n. 漂,漂流
    equip v.(with)装备,配备
    eager a.(for)渴望的,热切的
    expel v. 把……开除;驱逐;排出
    exact a. 确切地,正确地,恰好
    devil n. 魔鬼
    dwarf n.矮子,侏儒 v.(使)变矮小
    elder a. 年长的,资格老的 n. 长辈
    eject v. 喷射,排出;驱逐
    epoch n. 时期,时代
    drink v. 饮,喝,饮酒 n. 饮料
    drown v. 溺死,淹没
    evade vt.逃避,回避;避开,躲避
    earth n. 地球;土,泥;陆地;地上
    elect v. 选举,推选;选择,作出选择
    dress n. 服装,童装,女装 v. 穿衣,打扮
    doubt n./v. 怀疑,疑惑
    eagle n.鹰
    dizzy a. 头晕目眩的,眩晕的;(可能)使人头晕的,极高的
    dirty a. 弄脏的;下流的 v. 弄脏,玷污
    erect v. 树立,建立,使竖立 a. 直立的,垂直的
    delay v./n. 耽搁,延迟
    diary n. 日记,日记簿
    drama n. 剧本,戏剧;戏剧性事件或场面
    drill v./n. 练习,操练;钻孔
    drive v. 开(车),驾驶;驱,赶;驱动,把(钉;桩)打入 n. 驾驶,驱车旅行
    dwell v. 住,居留
    early a. 早的,早期的,及早的 ad. 早,在初期
    embed vt.使插入,使嵌入,深留,嵌入
    entry n. 进入,入口;通道;记载,条目
    equal a.(to)相等的;(to)胜任的 n.(地位)相等的人,对等的事物 v. 等于
    error n. 错误,过失
    essay n. 文章,短文
    event n. 事件,事情
    every a. 每一的,每个的;一切的,所有的
    excel vi.胜过其他;擅长 vt.胜过,优于
    exist v. 存在;生活
    fable n. 寓言
    faint a. 微弱的,不明显的 v. 昏过去
    fairy a.幻想中的;虚构的;优雅的 n.仙女;精灵
    faith n. 信任,信用;信仰,信条
    fancy n. 爱好,喜爱,迷恋 v. 想象,幻想 a. 花式的,奇特的,异样的
    fatal a. 致命的,毁灭性的
    fault n. 过失,过错;缺点,毛病
    favor n.(favour)好感;喜爱;关切v.赞成,支持,偏爱
    feast n. 节日;宴会 vt. 盛宴,款待,享乐,请客 vi. 参加宴会,享受
    fence n. 篱笆,围栏 n./v. 击剑
    ferry n. 渡船 v. 渡运(人、车或物等)
    fetch v. 取来,接来
    fever n. 发热,狂热
    fiber n.(fibre)纤维;构造;纤维制品
    field n. 田,田野;运动场;领域,方面;(电、磁等)场
    fifty num. 五十,五十个
    fight v./n. 打(仗),搏斗,斗争,战斗
    final a. 最终的,决定性的
    first num. 第一 a. 第一的,最先的 ad. 首先,最初
    flame n. 火焰,火苗;热情;光辉 v. 发火焰,燃烧
    flare v./n. 闪耀,闪烁
    flash n. 闪光 v. 发闪光,闪亮;闪现
    fleet n. 舰队,船队
    flesh n. 肉,肌肉
    fling v.(用力地)扔,抛,丢
    float v./n. 浮动,漂浮
    flock n.(一)群,(禽、畜等的)群;大量,众多 v. 群集,成群
    flood n. 洪水,水灾 v. 淹没,发大水,泛滥
    floor n. 地板,(楼房的)层
    flour n. 面粉
    fluid a. 流动的,流体的 n. 流体,液体
    flush v. 冲洗,奔流 n./v. 脸红 a.(with)齐平的,同高的
    focus n. 焦点,(活动、兴趣等的)中心 v.(on)使聚集,集中
    force n. 力量,力;势力;[pl.][总称]军队;兵力 v. 强迫,迫使
    forge v. 锻造,伪造 n. 锻工车间;锻炉
    forth ad. 向前,向外
    forty num. 四十,四十个
    forum n. 论坛,讨论会
    found v. 成立,建立,创办
    frame n. 框架,骨架 v. 装框子
    frank a. 坦白的,直率的
    fraud n.欺骗,欺诈行为,诡计,骗子,假货
    fresh a. 新的,新鲜的
    front a. 前面的,前部的 n. 前面,下面;前线,战线,阵线 v. 面对,朝向
    frost n. 霜,霜冻,严寒
    frown v. 皱眉
    fruit n. 水果,果实;成果,效果
    funny a. 滑稽的,可笑的
    gauge n.标准尺寸;规格;量规,量表 v.测量
    ghost n. 鬼魂,幽灵
    giant n. 巨人 a. 巨大的
    glare n./v. 怒视,瞪眼 v./n. 闪耀,闪光
    glass n. 玻璃;玻璃杯;镜子;[pl.]眼镜
    glide n./v. 溜,滑行
    globe n. 球体,地球仪;地球,世界
    glory n. 光荣,荣誉
    glove n. 手套
    goods n. 商品,货物
    goose n. 鹅
    grace n. 优美,文雅;恩惠,恩泽
    grade n. 等级,级别;年级;分数 v. 分等,分级
    grain n. 谷物,谷类;颗粒,细粒
    grand a. 盛大的,豪华的;重大的,主要的
    grant v. 同意,准予;给予,授予 n. 授予物
    grape n. 葡萄
    graph n. 图表,曲线图
    grasp v./n. 抓住,抓紧;掌握,领会
    grass n. 草
    grave n. 坟墓 a. 严肃的,庄重的
    graze v.放牧,吃草,擦伤,擦过 n.放牧,牧草,轻擦,擦破处
    great a. 大的,伟大的,重大的,极大的;美妙的
    Greek   n. 希腊人,希腊语 a. 希腊(人)的,希腊语的
    green a. 绿的,青的,未熟的,嫩的 n. 绿色;[pl.]蔬菜,植物
    greet v. 致敬,敬意,迎接;扑(鼻),入(耳),触(目)
    grief n.悲痛,伤心事,不幸,忧伤
    grind v. 磨(碎),碾(碎)
    groan v./n. 呻吟
    grope n./v.摸索,探索
    gross a. 总的,毛(重)的;粗鲁的,粗俗的 n. 总额
    group n. 群,组 v. 分组
    guard v./n. 守卫,保卫,提防 n. 哨兵,警卫
    guess v./n. 推测,猜测 v. 以为,相信
    guest n. 客人,宾客,旅客
    guide v. 为……领路,指导,引导 n. 领路人;指南,导游
    guilt n. 罪过,内疚
    habit n. 习惯,习性,脾性
    handy a. 手边的,近便的;方便的
    happy a. 幸福的,快乐的,乐意的
    harsh a.粗糙的,荒芜的,苛刻的,刺耳的,刺目的
    haste n. 匆忙,急速;草率 v. 赶快;匆忙
    hasty a. 匆忙的,仓促的;草率的
    hatch v. 孵,孵出;策划,图谋 n. 舱口,小门
    heart n. 心,心脏;中心,要点;内心,心肠
    heave v./n.举起
    heavy a. 重的,重型的;沉重的,大量的,猛烈的
    hedge n. 篱笆,树篱,障碍物 v. 用树篱围住
    hello int. 喂
    hence ad. 从此,今后;因此
    hinge n. 合页,绞链
    hobby n. 业余爱好,嗜好,兴趣
    hoist v. 举起,升起,吊起
    honey n. 蜜,蜂蜜
    honor n.尊敬,敬意;荣誉,光荣 v. 尊敬,给以荣誉
    horse n. 马
    hotel n. 旅馆
    hound n.猎犬 vt.带猎犬狩猎,追捕,激励,使追逐
    house n. 住宅,房子;议院,机构,所,社 v. 供宿,给房子住
    hover v.盘旋
    human a. 人的,人类的 n. 人
    humid a. 湿的,湿气重的
    humor n. 幽默,诙谐
    hurry v.(使)赶紧,(使)匆忙 n. 匆忙,仓促
    ideal a. 理想的,完美的;空想的;理想主义的;唯心的 n. 理想
    idiom n. 习语
    idiot n.白痴,愚人,傻瓜
    image n. 形象;肖像,影像,映像
    imply v. 意指,含……意思,暗示
    incur v. 招致,惹起,遭受
    index n.([pl.]indexes, indices)索引;指标,标志;指数 v. 附以索引,编入索引
    infer v. 推论,推断
    inlet n. 水湾,小湾;进口,入口
    inner a.内部的,里面的;内心的
    input n./v. 输入
    irony n.反话,讽刺,讽刺之事
    issue v. 流出,放出;发行,发表,颁布 n. 发行(物),(报刊)期号;问题,争论点,争端
    Japan   n. 日本
    jeans   n.斜纹布裤,牛仔裤
    jewel n. 宝石,宝石饰物
    joint n. 接合处,接头,接缝;关节,骨节 a. 联合的,共同的,连接的
    jolly a. 欢乐的,高兴的 ad. 非常
    judge n. 法官,审判员;裁判员,评判员,鉴定人 v. 审判,判决;评定,裁判;断定,判断
    juice n.(水果)汁,液
    kneel v. 跪,下跪
    knife n. 刀,餐刀 v. 用刀切,用匕首刺
    knock v. 敲,敲打,碰撞 n. 敲,击
    label n. 标签;标记,符号 v. 贴标签于……,把……称为
    labor n. 工作,劳动;劳力,劳工,劳方
    lapse n.失误,过失,流逝 v.失检,背离;堕入;流逝;失效
    large a. 大的,广大的,大规模的
    laser n. 激光
    later   ad. 后来,过后
    Latin   a. 拉丁的,拉丁文的 n. 拉丁语
    laugh v. 笑;(at)讥笑 n. 笑,笑声
    layer n. 层
    learn v. 学习,学,学会;(of /about)听到,获悉
    lease n.租借,租约,租赁物,租期,延续的一段时间 vt.出租,租出,租得
    least a. 最小的;最少的 ad. 最小,最少
    leave v. 离开,出发;留下,剩下,忘带;让,听任;交付,委托 n. 许可,准假,假期
    legal a. 法律的,法定的;合法的,正当的
    lemon n. 柠檬
    level n. 水平,水准;等级,级别 a. 水平的,平的 v. 弄平,铺平
    lever n. 杆,杠杆
    light n. 光,光亮,光线;灯,光源 v. 点(火)(使)变亮,照亮 a. 轻松的;(颜色)淡的,光亮的
    limit n. 界限,限度,范围 v.(to)限制,限定
    linen n. 亚麻布,亚麻布制品
    liner   n. 班机,班轮
    liter n.升[容量单位]
    litre n.(liter)升;公升(容量单位)
    liver n. 肝,肝脏
    lobby n. 门廊,门厅,(会议)休息厅
    local a. 地方的,当地的;局部的
    lodge v. 住宿,投宿,留宿
    lofty a.崇高的,高尚的;高傲的;极高的
    logic n. 逻辑,逻辑学
    loose a. 松的,肥大的
    lorry n. 卡车,运货汽车
    lover n. 爱好者;[pl.]情侣
    lower a. 较低的,下级的,下游的 v. 降下,放低
    loyal a.(to)忠诚的,忠贞的
    lucky a. 幸运的,侥幸的
    lunar a. 月的,月亮的
    lunch n. 午餐
    madam n.[常作 M-]女士,夫人,太太
    magic n. 魔法,魔术,戏法 a. 有魔力的,魔术的
    major a.(较)大的,(较)重要的 n. 专业,主修科目;专业学生;少校 v.(in)主修,专攻
    march v.(使)行军,(使)行进 n. 行军,行程;[M-]三月
    marry v. 结婚,嫁,娶
    match n. 火柴;比赛,竞赛;对手,敌手 v. 匹配,相配,相称
    maybe ad. 大概,或许
    mayor n. 市长
    means n. 方法,手段
    medal n. 奖章,勋章,纪念章
    melon n. 甜瓜
    mercy n. 仁慈,怜悯,宽恕
    merge v.合并,并入,结合,吞没,融合
    merit n. 优点,价值,功绩 v. 值得,应得
    merry a. 欢乐的,愉快的
    metal n. 金属,金属制品
    meter n. 计,表,仪表;米
    midst n. 中间,当中
    might aux. v. may的过去式;可能 n. 力量,威力,能力
    minor a. 较小的,较少的,较次要的 n. 兼修学科 v.(in)兼修
    minus a. 负的,减的 prep. 减去 n. 负号,减号
    model n. 样式,型;模范,典型;模型,原型,模特 v.(on, after)模仿
    moist a. 潮湿的,湿润的
    money n. 货币,钱
    month n. 月,月份
    moral a. 道德(上)的,道义的 n. 寓意,教育意义
    motel n.汽车旅馆
    motor n. 发动机,电动机
    mould n.(mold)模子,铸型 v.浇铸,造型,塑造
    mount v. 登上,爬上(山、梯等);安装,固定 n. 支架,底板;[M-][用于山名前]山峰
    mourn v. 哀悼,悲悼
    mouse n. 鼠,耗子
    mouth n. 口,嘴
    movie n. 电影,电影院
    music n. 音乐,乐曲
    naive a. 天真的
    naked a. 裸体的,无遮蔽的,无掩饰的
    nasty a. 肮脏的,卑劣的,下流的;令人厌恶的
    naval a. 海军的,军舰的
    Negro   n. 黑人 a. 黑人的
    nerve n. 神经;勇气,胆量
    never ad. 永不,从不,决不;从来没有
    niece n. 侄女,甥女
    night n. 夜,夜间
    ninth num. 第九
    noble a. 高尚的;贵族的,高贵的 n. 贵族
    noise n. 喧闹声,噪声,吵嚷声
    noisy n. 吵闹的,喧闹的
    north n. 北,北方,北部 a. 北方的,北部的 ad. 向北方,在北方
    novel n.(长篇)小说 a. 新奇的,新颖的
    nurse n. 护士,保姆 v. 护理,看护
    nylon n. 尼龙
    occur v. 发生,出现;想起,想到
    ocean n. 海洋
    offer v. 提供,提出,呈现,出现 n. 提议,提供
    often ad. 经常,常常,屡次
    onion n. 洋葱
    opera n. 歌剧
    orbit n. 轨道 v.(使)沿轨道行
    order n. 命令;次序,顺序;秩序,治安,正常状态,整齐;定购,定货单;等级 v. 制,定制,订购
    organ n. 器官;机构;风琴
    other a. 另外的,其它的,别的 pron. 别的东西,别人
    ought aux.(to + inf.)应当,应该,本应,本当
    ounce n. 盎司,英两
    outer a.外部的,外面的,外层的
    owing a.欠的,未付的
    owner n. 物主,所有者
    oxide n.[化]氧化物
    ozone n.新鲜的空气,[化]臭氧
    paint n. 油漆,颜料 v. 油漆;涂,涂漆;画;描绘,描述
    panda n. 熊猫
    panel n. 面,板;控制板,仪表盘;专门小组
    panic n. 恐慌,惊慌
    pants n.裤子, 短裤
    paper n. 纸;报纸;试卷;文章,论文;[pl.]官方文件 v. 裱糊
    party n. 聚会,政党,党派;一方,当事人
    paste n. 糊,浆糊 v. 粘,贴
    patch n. 补钉,补片;碎片,碎屑;小块,小片 v. 补,修补
    pause v./n. 中止,暂停
    peace n. 和平;平静,安宁
    peach n. 桃,桃树
    pearl n. 珍珠
    pedal n. 踏板 v. 踩踏,骑自行车
    penny n. 便士,美分
    petty a.小的,琐碎的;气量小的
    phase n. 阶段,状态,时期;相,相位
    phone n. 电话,电话机 v.(给……)打电话
    photo n. 照片
    piano n. 钢琴
    piece n.(一)件,(一)片,(一)篇;碎片,断片 v.(together)拼合,拼凑
    pilot n. 飞行员,驾驶员;领港员,引水员 v. 驾驶(飞机等);领航,引水
    pinch v. 捏,掐,拧,挟 n. 捏,掐;(一)撮,微量
    pitch n. 沥青;掷 v. 用沥青覆盖;投掷,扔
    place n. 地方,地点;名次;地位,职位;寓所 v. 安排,任命;放置;投(资)
    plain a.明白的,平易的;朴素的,平常的;坦率;平凡,普通 n. 平原,旷野
    plane n. 飞机;平面,水平面
    plant n. 植物,作物;工厂;装置v. 栽种,播种,栽培
    plate n. 金属板,片;盘子,盆子;板,钢板 v. 镀,电镀
    plead v. 恳求,请求;为……辩护;提出……为理由(或借口)
    point n. 尖,尖端;点,小数点;条款,细目;分数 v.(at, to)指,指向,表明
    polar a.两极的,极地的,南辕北辙的 n.极线,极面
    porch n. 门廊
    pound   n. 磅;英镑 v.(连续)猛击,(猛烈)敲打,捣碎
    power n. 力,能力,精力;功率,动力,电力;[数学]幂,乘方;权力,势力,政权
    press v. 压,揿,按;压迫;紧迫,催促,逼迫 n. 报刊,出版社,通讯社,压榨机,压力机;揿,按
    price n. 价格,价钱;代价 v. 标价
    prick v. 刺伤,刺痛,刺孔 n. 刺伤,刺痛
    pride n. 自豪,自尊心;自满,骄傲,傲慢;引以自豪的东西 v. 使自豪,使自夸
    prime a. 首要的,主要的;最好的,第一流的 n. 青春,全盛期,青壮年时期
    print n. 印刷,印刷品,字体 v. 印刷,出版;洗印
    prior a./ad. 优先的,在前的;(to)在……之前
    prize n. 奖赏,奖金,奖品 v. 珍视,珍惜
    probe n. 探针,探测器 v.(以探针等)探查,穿刺,查究
    prone a. 易于…的,很可能…的;俯卧的
    proof n. 证据,证明;校样,样张
    prose n.散文 a.散文的
    proud a.(of)自豪的;得意的;骄傲的,引以自豪的;妄自尊大的
    prove v. 证明,证实;检验;考验;鉴定;结果是,表明是
    pulse n. 脉搏,脉冲
    punch n. 冲压机,冲床;穿孔机 v. 冲压,穿孔
    pupil n. 学生,小学生;瞳孔
    purse n. 钱包
    quart n. 夸脱
    queen n. 女王,皇后,王后
    queer a.奇怪的,古怪的
    quest n.探寻,探求;寻求,追求
    queue n. 行列,长队 v.(up)排队,排队等待
    quick a. 快的,迅速的;灵敏的,敏捷的,伶俐的;性急的,敏锐的 ad. 快,迅速地
    quiet a. 安静的,平静的 n. 安静,平静 v. 使安静,平静
    quilt n. 被子
    quite ad. 十分,完全;相当,颇;的确,真正
    quota n.配额,限额
    quote v. 引用,援引
    radar n. 雷达
    radio n. 收音机,无线电报,无线电话 v. 用无线电通讯
    raise v. 举起,提高,提升;增加;饲养,养育;引起;竖起;提出,发起
    rally n. 集会;公路汽车赛 v. 集合,团结;恢复(健康等),重新振作
    range n. 范围,距离,领域;排列,连续;(山)脉;炉灶 v. 排列成行
    rapid a. 快,急速的 n. [pl.]急流,湍滩
    ratio n. 比,比率
    razor n. 剃刀
    reach v. 抵达,达到;(out)伸手,够到,触到 n. 能达到的范围
    react v. 反应,起作用;(against)反对,起反作用
    ready a.(for)准备好的,现成的;甘心的
    realm n. 王国,国土;领域
    rebel v. 反抗,反叛,起义 n. 叛逆者,起义者
    recur vi.复发,重现,再来
    refer v. 参考,查阅,查询;(to)提到,引用;提交,上呈
    reign v.(over)统治,支配;盛行,占优势 n. 统治,统治时期,支配;朝代
    relax v.(使)松弛,放松
    relay v. 中继,转播,接力 n. 接替人员,替班
    renew v.(使)更新,恢复,重新开始,继续
    repay v. 付还,偿还;报答
    repel v. 击退,抵制,拒绝,排斥
    reply v./n.(to)回答,答复,以……作答
    ridge n. 岭,山脉;屋脊;鼻梁
    rifle n. 步枪
    right a. 正确的,对的,合适的,恰当的;右边的,右方的;正常的,健康的;直角的,直的 ad. 对,不错;直接地,径直地;正好,完全 n. 权利,法权;右面
    rigid a.刚性的;刻板的;严厉的
    rival n. 竞争者,对手 v. 竞争,对抗 a. 竞争的
    river n. 河流
    roast v. 烤,炙,烘
    robot n. 机器人,自动机械
    Roman   a. 罗马的,罗马数字的,罗马人的 n. 罗马人
    rough a. 粗糙的;粗略的,大致的;粗野的,粗暴的
    round a. 圆的,球形的 prep.围绕 ad. 在周围 v. 绕行;使成圆形 n.(一)回合,(一)圈,巡回
    rouse v. 惊起;唤起,唤醒
    route n. 路线,路程
    royal a. 王室的,皇家的;第一流的,高贵的
    ruler n. 统治者,支配者;尺,直尺
    rumor n. 传闻,谣言
    rural a. 农村的
    saint n. 圣人,圣徒;[S-或略作St.,用于人、地名前]圣
    salad n. 色拉,凉拌菜
    sauce n. 酱汁,调味汁
    scale n. 刻度,标度;天平,磅秤;比例尺;规模;音阶;鱼鳞
    scare n. 惊恐,恐慌 v. 惊吓,受惊
    scarf n. 围巾,头巾
    scene n. 景色,景象,舞台;(戏)一场
    scent n. 气味,香味;香水
    scold v. 责骂,训斥
    scope n.(活动)范围;机会,余地
    score n. 得分,分数;二十 v. 得(分),记(……的)分数
    scorn v./n. 轻蔑,藐视
    scout n. 侦察员,侦察机(舰) v. 搜索,侦察
    scrap n. 碎片;废料 v. 废弃,报废
    screw n. 螺旋,螺丝(钉) v. 拧,拧紧
    seize v. 抓住,逮住;夺取,占领;没收,查封
    sense n. 感官,官能;感觉;判断力;见识;意义,意思 v. 觉得,意识到
    serve v. 服务,尽责;招待,侍候;符合,适用
    seven num. 七,七个
    shade n. 荫,阴影;遮光物,罩 v. 遮蔽,遮光
    shady a. 成荫的,多荫的;可疑的,靠不住的
    shaft n. 轴;杆状物
    shake n./v. 摇动,摇;颤抖,震动
    shall aux. v. 将要,将;必须,应该;就,该
    shame n. 羞耻,羞愧,耻辱;可耻的人(或事物) v. 使羞愧,玷辱
    shape n. 形状,外形;情况,状态;种类 v. 成型,塑造
    share v.(with)分配,均分,共享;分享,分担 n. 一份,份额;股份
    shark n. 鲨鱼
    sharp a. 锋利的,锐利的;轮廓分明的,鲜明的;急转的,突然的;刺耳的;敏锐的,机警的 ad.(指时刻)正,准
    shave v. 剃,刮,刨,削 n. 刮脸
    shear v. 剪,修剪
    sheep n. 羊,绵羊
    sheer a. 完全的,十足的;陡峭的,垂直的;极薄的,透明的
    sheet n. 被单;(一)张,(一)片,薄片;大片
    shelf n. 架子,搁板
    shell n. 壳,贝壳;炮弹
    shift v. 替换,转换;移动 n. 转换,转变;(轮)班,(换)班
    shine v. 照耀,发光;擦亮 n. 光泽,光
    shirt n. 衬衫
    shock n. 震动,冲击;触电;震惊;休克 v.(使)震惊;(使)休克
    shoot v. 发射,射击;掠过,疾弛而过;发芽 n. 嫩枝,苗,射击,发射
    shore n. 海滨,湖滨
    short a.短的,矮的;(of)缺乏,不足 n. [pl.]短裤
    shout v./n. 呼喊,呼叫
    shove n.〈口〉推,挤 v.〈口〉推挤,猛推,强使
    shrug n./v.耸肩
    siege v./n.包围,围攻
    sight n. 视力,视觉;望见,瞥见;视域;眼界;情景,奇观
    silly a. 傻的,糊涂的,愚蠢的
    since prep.自从 conj.自从;因为,既然  ad.后来
    siren n. 警报声,警报器;妖妇
    skate v. 溜冰,滑冰 n. 冰鞋
    skill n. 技能,技巧,手艺;熟练
    skirt n. 裙子;边缘,郊区
    skull n.头脑,头骨
    slack a. 懈怠的,不紧的;萧条的 n. 淡季,萧条;[pl.]便裤,运动裤
    slave n. 奴隶,苦工 v. 做苦工,拼命地干
    sleep n./v. 睡(眠)
    slice n. 薄片,切片;一份;部分切(片)
    slide v.(使)滑动,滑行 n. 滑坡,滑道;滑,滑动;幻灯片
    slope n. 斜坡,斜面;倾斜,斜度 v.(使)倾斜
    small a. 小的,少的
    smart a. 漂亮的,潇洒的;聪明的;巧妙的,伶俐的 v. 剧痛,刺疼
    smash v./n. 打碎,粉碎
    smell n. 嗅,闻到;散发(……的)气味,有(……的)气味
    smile v./n. 微笑
    smoke n. 烟,烟尘;吸烟,抽烟v. 抽(烟);冒烟,冒气
    snack n. 快餐,小吃,点心
    snake n. 蛇
    sneak v.偷偷地走,潜行;〈口〉偷窃 n.鬼鬼祟祟的人
    sniff v.用力吸气,嗅,闻到,发觉,轻视
    sober a. 清醒的;认真的,冷静的,适度的
    solar a. 太阳的,日光的
    solid a. 固体的;实心的;结实的,稳固的,可靠的 n. 固体
    solve v. 解决,解答
    sorry a.(for, about)遗憾的,对不起的;可怜的
    sound n. 声音,声响 v. 发声,响;听起来 a. 健全的,完好的;正当的,有根据的;彻底的,充分的
    south n. 南,南方,南部 a. 南方的,南部的
    space n. 间隔,距离;空地,余地;空间,太空 v. 留间隔,隔开
    spade n. 铁锹,铲子
    spare a. 多余的,剩下的,备用的 v. 节约,节省;让给,抽出(时间)
    spark n. 火花,火星 v. 发火花,发电花
    speak v. 说,说话;表示意见;演说,发言
    spear n. 矛,枪
    speed v. 迅速,前进,急行;加速,催,使加速
    spell v. 拼写
    spend v. 花费;消耗,用尽;度过,消磨
    spicy a.辛辣的,加香料的,有风味的,粗俗的
    spill v. 溢出,溅出 n. 摔下,跌下
    spine n.脊柱,书脊
    spite n. 恶意;怨恨
    split v. 裂开,劈开;分裂,分离 n. 分化,分裂,裂口
    spoil v. 损坏,搞错;宠坏,溺爱
    spoon n. 匙,调羹
    sport n. 运动;[pl.]运动会
    spray n. 喷雾,飞沫,浪花,水花 v. 喷,喷射
    stack n. 堆,一堆 v. 堆积,堆起
    staff n. 全体职工;杠,棒;参谋部 v. 配备工作人员
    stage n. 舞台,戏剧;阶段,时期
    stain n. 污点,瑕疵 v. 玷污;染色
    stair n. [常pl.]楼梯
    stake n. 桩,标桩;赌注,利害关系
    stale a. 变质的,不新鲜的;陈旧的,陈腐的
    stalk n.茎,柄,梗,秆 v. 昂首阔步的走
    stall n. 货摊;畜栏,厩 v.(使)停转,(使)停止
    stamp n. 邮票,印花;印;跺脚,顿足;标志,印记 v. 跺脚,顿足;盖章,盖印
    stand v. 站,站立;坐落,位于;坚持,维持原状;经受,忍受 n. 台座
    stare v.(at)盯,凝视
    start v. 开始,着手;动身,出发;吃惊;开办,开动 n. 开端,起点;惊起,吃惊
    state n. 状态,情况;国,州 v. 陈述,说明
    steak n.牛排,肉排,肉片,鱼片
    steal v. 偷,窃取;偷偷地做,巧取
    steam n. 水汽,蒸汽,水蒸汽 v. 蒸发;蒸;用蒸汽开动
    steel n. 钢
    steep a. 陡峭的,险峻的;(价格)过高的;(升降)急剧的 v. 浸泡,沉浸
    steer v. 驾驶,掌舵
    stern a. 严厉的,苛刻的;坚决的,坚定的 n. 船尾,舟尾
    stick n. 棍,棒,手杖 v. 刺,戳,扎;粘贴
    stiff a. 硬的,僵直的;拘谨的;呆板的;艰难地,费尽的
    still ad. 还,仍旧;还要;静 a. 静止的,寂静的 n. 寂静
    sting v./n. 刺,刺痛,剧痛;刺,叮
    stock n. 备料,库存,现货;股票,公债 v. 储存
    stone n. 石,石头;宝石;果核
    stool n. 凳子
    stoop v. 弯腰,俯身 n. 弯腰,曲背
    store n. 商店,店铺;贮藏,贮备品 v. 贮藏,贮备
    storm n. 暴风雨,暴风雪;激动,爆发 v. 猛攻,直捣
    story n. 故事,传说,小说;楼层
    stove n. 炉子,火炉
    strap n. 带,皮带 v. 捆扎
    straw n. 稻草,麦杆;吸管
    strip v. 剥,剥去 n. 窄条,条纹
    study v. 学习,研究,细察,仔细端详 n. 学习,书房
    stuff n. 原料,材料,东西 v. 填满,塞满
    style n. 风格,文体;式样,时式,类型
    sugar n.糖
    suite n.(一批)随员,(一套)家具,套房
    super a. 极好的,超级的
    surge n./v.汹涌,澎湃;(感情)起伏,高涨
    swamp n. 沼泽,沼地
    swarm n. 群,蜂群 v. 云集,充满
    swear (at)v.诅咒,骂人;宣誓,发誓
    sweat n. 汗v.(使)出汗
    sweep v. 扫,打扫;席卷,冲光;扫过,掠过
    sweet a. 甜的;可爱的,美好的;芳香的 n.[常pl.]糖果;甜食
    swell v. 使膨胀,增大,隆起
    swift a. 快速的,敏捷的
    swing vi. 摇摆;回转 n. 摇摆,摆动;秋千
    sword n. 剑,刀
    table n. 桌子,台子;目录,表格
    taboo n./v. 禁忌
    taste v. 品尝,辨味;(of)有……味道;体验,感到 n. 滋味,味觉;(趣)味,鉴赏力
    teach v. 教,教授,教训
    tease v. 戏弄,取笑;挑逗,撩拨 n. (爱)戏弄他人者;戏弄,挑逗
    tempo n. 节奏,行进速度;(音乐的)速度
    tempt v. 诱惑,引诱;吸引,使感兴趣
    tense n. 时态 a. 拉紧的,紧张的
    thank v./n. 感谢
    theft n. 偷窃,失窃
    their pron.[they的所有格] 他(她、它)们的
    theme n. 题目,主题
    there ad. 在那里,往那里;在这方面,在这点上;[用以引起注意];[与be连用,表示"有"];[放在句首用以加强语气]
    these pron./a. 这些;这些人(东西)
    thick a. 厚的,粗的,稠的,浓的 ad. 厚,浓,密
    thief n. 小偷,贼
    thigh n.大腿,股
    thing n. 东西,物;事(件);[pl]所有物,用品;[pl]事态,情况
    think v. 想,思索;认为,以为;考虑,打算
    third num. 第三,三分之一
    thorn n. 刺,荆棘
    those pron./a.[that的复数]那些;那些人(东西)
    three num./a. 三,三个
    throw v. 扔,投,掷
    thumb n. 拇指
    tiger n. 虎
    tight a. 紧的;紧身的,装紧的;密封的,不透……的 ad. 紧紧地
    timid a. 胆怯的,怯懦的
    tired a. 疲劳的;厌倦的
    title n. 书名,标题;头衔,称号
    toast n. 烤面包,吐司,祝酒(词) v. 烘,烤;(向……)祝酒
    today ad./n. 今天;现在,现今
    token n. 表示;标志,象征;记号;信物;纪念品;礼卷,代价券;筹码 a. 象征性的
    tooth n. 牙齿,齿;齿状物
    topic n. 话题,主题,题目
    torch n. 手电筒,火炬,火把
    total n. 总数,总计 a. 总的,全部的,完全的 v. 合计,总数达
    touch v. 触,碰,摸;感动,触动;涉及,论及 n. 触动,碰到;少许,一点
    tough a. 坚韧的,棘手的,困难的;强健的,吃苦耐劳的;粗暴的,凶恶的
    towel n. 毛巾
    tower n. 塔 v. 高耸
    toxic a.有毒的,中毒的
    trace n. 痕迹,踪迹;极少量,微量 v. 描绘;跟踪,追踪
    track n. 跑道,小路;轨迹,轮迹 v. 跟踪,追踪
    trade n. 贸易,商业;职业,行业 v. 经商,交易
    trail n. 踪迹,痕迹;(乡间)小道 v. 追踪,跟踪
    train n. 列车,火车;行列,系列,一串 v. 训练,培养
    trait n. 特征,特点,特性
    tramp n. 流浪者,步行,跋涉 v. 步行,跋涉
    trash n.无价值之物,垃圾,废物
    treat v. 对待;处理;治疗;论述,探讨;款待,请客 n. 款待,请客
    trend n. 倾向,趋势 v. 伸向,倾向
    trial n. 审讯;试验,考验
    tribe n. 部落,家族
    trick n. 诡计,骗局;恶作剧;窍门,诀窍 v. 欺骗,哄骗
    troop n.[pl.]部队,军队;(一)群,(一)队
    truck n. 卡车,载重汽车
    trunk n. 大衣箱,皮箱;(汽车后部)行李箱;树干,躯干
    trust v. 信任,信赖;盼望,希望;委托 n.(in)信任,依赖;委托,信托
    truth n. 真实,真相;真实性,忠实性;真理
    tutor n. 家庭教师,指导教师 v. 个别指导
    twice ad. 两次,两倍
    twist v. 捻,搓;绞,拧;歪曲,曲解 n. 搓,拧;扭转,扭弯

     

    uncle

    n. 伯父,叔父,舅父,姑父,姨父

    under

    prep. 在……下面;在……下面;少于,低于;在……情况下,在……中

    unify

    v. 使联合,统一;使相同,使一致

    union

    n. 协会,工会,同盟;联合,合并;一致,融洽

    unite

    v. 联合,团结;统一,合并

    unity

    n. 团结;统一,一致,整体

    until

    prep./conj. 直到……为止

    upper

    a. 上面的;上部的,较高的

    upset

    v. 扰乱,使……心烦意乱;打翻,推翻

    urban

    a. 城市的

    usage

    n. 用法,惯用法

    usual

    a. 通常的,平常的

    utter

    v. 说,发出(声音) a. 彻底的,完全的

    vague

    a. 不明确的,含糊的,暧昧的

    valid

    a. 有效的;合理的,有根据的

    value

    n. 价格;价值;实用性;重要性 v. 评价,估价;尊重,重视

    valve

    n.阀;[英]电子管,真空管

    verge

    n. 边,边缘 v. 接近,濒临

    verse

    n. 韵文,诗;诗节,诗句

    video

    n. 电视,视频;录像 a. 电视的,视频的;录像的

    virus

    n. 病毒;(精神、道德方面的)有害影响

    visit

    n. 访问,参观,作客 v. 访问,参观;视察,巡视;常去

    vital

    a. 生死攸关的,重大的;生命的,生机的

    vivid

    a. 鲜艳的;生动的,栩栩如生的

    vocal

    a.声音的,有声的,口头的,歌唱的 n.元音,声乐作品

    voice

    n. 声音,噪音;嗓子,发声能力;语态 v. 说出,表达

    vowel

    n. 元音,元音字母

    waist

    n. 腰,腰部

    waken

    v. 醒,弄醒,唤醒

    waste

    v. 浪费,耗费 a. 无用的,废弃的;荒芜的 n. 浪费;废物

    watch

    v. 观看,注视;看守,监视;(for)窥伺,等待 n. 表;看管,监视

    water

    n. 水 v. 洒水,浇水

    weary

    a. 疲倦的;令人厌烦的 v. 使疲倦,使厌烦

    weave

    v. 编,编织

    wedge

    n. 楔,楔形 v. 楔牢,楔入,挤进

    weigh

    v. 称……重量,称;重达;考虑,权衡

    weird

    a.怪异的,超自然的,神秘的,不可思议的

    whale

    n.鲸 v.捕鲸

    wheat

    n. 小麦

    wheel

    n. 轮,车轮

    where

    ad. 在哪里,往哪里;在……的(地方) conj.在……地方,到……地方 pron.哪里,什么地方

    which

    pron. 哪一个,哪一些;那一个,那一些 a. 哪一个,哪一些

    while

    conj.(=whilst)当……时,和……同时;而,然而;尽管,虽然 n. 一段时间,一会儿v.(away)消磨(时间)

    whirl

    v.(使)旋转,打转n. 旋转,急转

    white

    a. 白色的,白的;白种的n. 白色,白人

    whole

    a. 完整的,无缺的,全部的,全体的 n. 全部,全体,完整

    whose

    pron. 谁的;[引出定语从句]那个人的,那些人的

    widow

    n. 寡妇

    width

    n. 宽度;宽阔,广阔

    witch

    n.巫婆,女巫 vt.施巫术,迷惑

    woman

    n. 女人

    world

    n. 世界;……界,领域;全世界,世人

    worry

    v. 烦恼,多愁;(about)对……感到烦恼,对……发愁 n. 烦恼,焦虑,担忧

    worse

    a./ad. 更坏,更差(的/地)

    worst

    a./ad. 最坏(的)最差(的)

    worth

    n. 价值a. 值……的,价值……的,值得……的

    would

    aux. v. will的过去式;[表示语气委婉的请求]愿;[表示过去的习惯]常常,大概

    wound

    n. 伤口,创伤 v. 伤,伤害

    wreck

    n. 失事(船或飞机),残骸,失事 v.(船等)失事,遇难;破坏,拆毁

    wrist

    n. 腕,腕关节

    write

    v. 写,写(字,信,函)

    wrong

    a. 错误的,不正确的;不道德的,不正当的 ad. 错,不对

    X-ray 

    n. X射线,X光

    yeast

    n. 酵母

    yield

    v. 出产,长出;(to)屈服,服从 n. 产量,收获

    young

    a. 年轻的n. 青年人

    yours

    pron.[you的物主代词] 你(们)的(东西)

    youth

    n. 青春;年轻人

    zebra

    n. 斑马

    更多相关内容
  • C#: 生辰八字五行计算算法

    千次阅读 2016-12-30 10:15:59
    最近偶有机缘接触到八卦五行,有个校友在做紫微斗数,于是乎就想做个计算生辰八字五行算法的C#代码,说到底占卜命理这种理论笔者觉得最终还是基于统计学的,这个可能有很多学派很多师傅有不同的理论,不过算生辰八字...

    最近偶有机缘接触到八卦五行,有个校友在做紫微斗数,于是乎就想做个计算生辰八字五行算法的C#代码,说到底占卜命理这种理论笔者觉得最终还是基于统计学的,这个可能有很多学派很多师傅有不同的理论,不过算生辰八字还算是通用的,不过不能乱算,笔者最不喜欢的就是搞个不靠谱的误人子弟,于是乎研究了一圈,发现有篇潘爱民写的还算比较可靠,但是是基于c语言的,于是笔者在这基础上写了个C#版的,本着源于网络回馈网络的精神下面是C#改写的代码,望大家交流,有其他占卜相关的算法也可以一起研究,其实这和大数据还真的能结合一起。

        public class BaziAlgorithm
        {
            //==================================
            //以下为http://blog.csdn.net/panaimin/article/details/8544489
            //计算五行


            const string TianGan = "甲乙丙丁戊己庚辛壬癸";
            const string DiZhi = "子丑寅卯辰巳午未申酉戌亥";


            public bool CheckBazi(string bazi)
            {


                int baziLen;


                int i, j;






                baziLen = bazi.Length;


                if (baziLen != 6 && baziLen != 8) return false;






                for (i = 0; i < baziLen;)
                {


                    char ch = bazi[i];


                    for (j = 0; j < 10; j++)


                        if (ch == TianGan[j]) break;


                    if (j >= 10) return false;


                    i++;






                    ch = bazi[i];


                    for (j = 0; j < 12; j++)


                        if (ch == DiZhi[j]) break;


                    if (j >= 12) return false;


                    i++;


                }






                return true;


            }






            /*


            根据出生日子的天干,通过下表来查算时辰干支:


            时辰干支查算表


            时间时辰                             五行纪日干支


                                   甲己     乙庚     丙辛     丁壬     戊癸






            23-01 子/水           甲子     丙子     戊子     庚子     壬子


            01-03 丑/土           乙丑     丁丑     己丑     辛丑     癸丑


            03-05 寅/木           丙寅     戊寅     庚寅     壬寅     甲寅


            05-07 卯/木           丁卯     己卯     辛卯     癸卯     乙卯


            07-09 辰/土           戊辰     庚辰     壬辰     甲辰     丙辰


            09-11 巳/火           己巳     辛巳     癸巳     己巳     丁巳


            11-13 午/火           庚午     壬午     甲午     丙午     戊午


            13-15 未/土           辛未     癸未     乙未     丁未     己未


            15-17 申/金           壬申     甲申     丙申     戊申     庚申


            17-19 酉/金           癸酉     乙酉     丁酉     己酉     辛酉


            19-21 戊/土           甲戌     丙戌     戊戌     庚戌     壬戌


            21-23 亥/水           乙亥     丁亥     己亥     辛亥     癸亥






            */


            string[][] cTimeGanZhi_Table = new string[12][]


    {


            new string[] {"甲子","丙子","戊子","庚子","壬子"},


            new string[] {"乙丑","丁丑","己丑","辛丑","癸丑"},


            new string[] {"丙寅","戊寅","庚寅","壬寅","甲寅"},


            new string[] {"丁卯","己卯","辛卯","癸卯","乙卯"},


            new string[] {"戊辰","庚辰","壬辰","甲辰","丙辰"},


            new string[] {"己巳","辛巳","癸巳","己巳","丁巳"},


            new string[] {"庚午","壬午","甲午","丙午","戊午"},


            new string[] {"辛未","癸未","乙未","丁未","己未"},


            new string[] {"壬申","甲申","丙申","戊申","庚申"},


            new string[] {"癸酉","乙酉","丁酉","己酉","辛酉"},


            new string[] {"甲戌","丙戌","戊戌","庚戌","壬戌"},


            new string[] {"乙亥","丁亥","己亥","辛亥","癸亥"}


    };






            static string sBuf;        // 用作八字结果缓冲区






            // 根据出生年月日的干支计算时辰干支


            // 输入参数:bazi,年月日的干支,即八字中的前六个字


            // 输入参数:hour,出生时间的小时数,-1~22


            // 输出结果:八字字符串,Unicode编码


            public string ComputeTimeGan(string bazi, int hour)


            {
                if (hour > 22) hour -= 24;
                char dayGan = bazi[4];






                int indexX, indexY;






                int i;


                for (i = 0; i < 10; i++)


                    if (dayGan == TianGan[i]) break;


                if (i >= 10) return "";


                indexX = i;


                if (indexX >= 5) indexX -= 5;


                indexY = (hour + 1) / 2;






                sBuf = bazi;


                sBuf += cTimeGanZhi_Table[indexY][indexX];






                return sBuf;


            }






            /*


            十二月份天干强度表


            生月\四柱天干        甲              乙              丙              丁              戊              己              庚              辛              壬              癸


            子月                            1.2             1.2             1.0             1.0             1.0             1.0             1.0             1.0             1.2             1.2


            丑月                            1.06 1.06 1.0             1.0             1.1             1.1             1.14 1.14 1.1             1.1


            寅月                            1.14 1.14 1.2             1.2             1.06 1.06 1.0             1.0             1.0             1.0


            卯月                            1.2             1.2             1.2             1.2             1.0             1.0             1.0             1.0             1.0             1.0


            辰月                            1.1             1.1             1.06 1.06 1.1             1.1             1.1             1.1             1.04 1.04


            巳月                            1.0             1.0             1.14 1.14 1.14 1.14 1.06 1.06 1.06 1.06


            午月                            1.0             1.0             1.2             1.2             1.2             1.2             1.0             1.0             1.0             1.0


            未月                            1.04 1.04 1.1             1.1             1.16 1.16 1.1             1.1             1.0             1.0


            申月                            1.06 1.06 1.0             1.0             1.0             1.0             1.14 1.14 1.2             1.2


            酉月                            1.0             1.0             1.0             1.0             1.0             1.0             1.2             1.2             1.2             1.2


            戌月                            1.0             1.0             1.04 1.04 1.14 1.14 1.16 1.16 1.06 1.06


            亥月                            1.2             1.2             1.0             1.0             1.0             1.0             1.0             1.0             1.14 1.14


            */






            double[][] TianGan_Strength = new double[12][]


            {


            new double[] {1.2, 1.2,  1.0,  1.0,  1.0,  1.0,  1.0,  1.0,  1.2,  1.2},


             new double[]{1.06,        1.06,         1.0,  1.0,  1.1,  1.1,  1.14,         1.14,         1.1,  1.1},


            new double[] {1.14,        1.14,         1.2,  1.2,  1.06,         1.06,         1.0,  1.0,  1.0,  1.0},


            new double[] {1.2, 1.2,  1.2,  1.2,  1.0,  1.0,  1.0,  1.0,  1.0,  1.0},


            new double[] {1.1, 1.1,  1.06,         1.06,         1.1,  1.1,  1.1,  1.1,  1.04,         1.04},


            new double[] {1.0, 1.0,  1.14,         1.14,         1.14,         1.14,         1.06,         1.06,         1.06,         1.06},


            new double[] {1.0, 1.0,  1.2,  1.2,  1.2,  1.2,  1.0,  1.0,  1.0,  1.0},


            new double[] {1.04,        1.04,         1.1,  1.1,  1.16,         1.16,         1.1,  1.1,  1.0,  1.0},


            new double[] {1.06,        1.06,         1.0,  1.0,  1.0,  1.0,  1.14,         1.14,         1.2,  1.2},


            new double[] {1.0, 1.0,  1.0,  1.0,  1.0,  1.0,  1.2,  1.2,  1.2,  1.2},


            new double[] {1.0, 1.0,  1.04,         1.04,         1.14,         1.14,         1.16,         1.16,         1.06,         1.06},


            new double[] {1.2, 1.2,  1.0,  1.0,  1.0,  1.0,  1.0,  1.0,  1.14,         1.14}


            };






            /*


            十二月份地支强度表






                                    生月       子月         丑月         寅月         卯月         辰月         巳月         午月         未月         申月         酉月         戌月         亥月        


            地支         支藏


            子              癸                       1.2             1.1             1.0             1.0             1.04 1.06 1.0             1.0             1.2             1.2             1.06 1.14


            丑              癸                       0.36 0.33 0.3             0.3             0.312        0.318        0.3             0.3             0.36 0.36 0.318        0.342


            丑              辛                       0.2             0.228        0.2             0.2             0.23 0.212        0.2             0.22 0.228        0.248        0.232        0.2           


            丑              己                       0.5             0.55 0.53 0.5             0.55 0.57 0.6             0.58 0.5             0.5             0.57 0.5            


            寅              丙                       0.3             0.3             0.36 0.36 0.318        0.342        0.36 0.33 0.3             0.3             0.342        0.318       


            寅              甲                       0.84 0.742        0.798        0.84 0.77 0.7             0.7             0.728        0.742        0.7             0.7             0.84


            卯              乙                       1.2             1.06 1.14 1.2             1.1             1.0             1.0             1.04 1.06 1.0             1.0             1.2            


            辰              乙                       0.36 0.318        0.342        0.36 0.33 0.3             0.3             0.312        0.318        0.3             0.3             0.36


            辰              癸                       0.24 0.22 0.2             0.2             0.208        0.2             0.2             0.2             0.24 0.24 0.212        0.228       


            辰              戊                       0.5             0.55 0.53 0.5             0.55 0.6             0.6             0.58 0.5             0.5             0.57 0.5            


            巳              庚                       0.3             0.342        0.3             0.3             0.33 0.3             0.3             0.33 0.342        0.36 0.348        0.3            


            巳              丙                       0.7             0.7             0.84 0.84 0.742        0.84 0.84 0.798        0.7             0.7             0.728        0.742       


            午              丁                       1.0             1.0             1.2             1.2             1.06 1.14 1.2             1.1             1.0             1.0             1.04 1.06


            未              丁                       0.3             0.3             0.36 0.36 0.318        0.342        0.36 0.33 0.3             0.3             0.312        0.318       


            未              乙                       0.24 0.212        0.228        0.24 0.22 0.2             0.2             0.208        0.212        0.2             0.2             0.24


            未              己                       0.5             0.55 0.53 0.5             0.55 0.57 0.6             0.58 0.5             0.5             0.57 0.5            


            申              壬                       0.36 0.33 0.3             0.3             0.312        0.318        0.3             0.3             0.36 0.36 0.318        0.342       


            申              庚                       0.7             0.798        0.7             0.7             0.77 0.742        0.7             0.77 0.798        0.84 0.812        0.7            


            酉              辛                       1.0             1.14 1.0             1.0             1.1             1.06 1.0             1.1             1.14 1.2             1.16 1.0            


            戌              辛                       0.3             0.342        0.3             0.3             0.33 0.318        0.3             0.33 0.342        0.36 0.348        0.3            


            戌              丁                       0.2             0.2             0.24 0.24 0.212        0.228        0.24 0.22 0.2             0.2             0.208        0.212       


            戌              戊                       0.5             0.55 0.53 0.5             0.55 0.57 0.6             0.58 0.5             0.5             0.57 0.5            


            亥              甲                       0.36 0.318        0.342        0.36 0.33 0.3             0.3             0.312        0.318        0.3             0.3             0.36


            亥              壬                        0.84 0.77 0.7             0.7             0.728        0.742        0.7             0.7             0.84 0.84 0.724        0.798       


            */


            struct ZISTRENGTH
            {


                public char diZhi;


                public char zhiCang;


                public double[] strength;


                public ZISTRENGTH(char a, char b, double[] c)
                {
                    diZhi = a; zhiCang = b; strength = c;
                }


            };




            ZISTRENGTH[] DiZhi_Strength = new ZISTRENGTH[]


            {


            new ZISTRENGTH ('子', '癸', new double[] {1.2,1.1, 1.0, 1.0,        1.04, 1.06, 1.0,1.0, 1.2, 1.2, 1.06, 1.14}),


             new ZISTRENGTH('丑', '癸', new double[] {0.36,0.33, 0.3, 0.3, 0.312, 0.318, 0.3, 0.3, 0.36, 0.36, 0.318, 0.342}),


             new ZISTRENGTH('丑', '辛', new double[] {0.2,0.228, 0.2, 0.2, 0.23, 0.212, 0.2,         0.22,0.228, 0.248, 0.232, 0.2}),


             new ZISTRENGTH('丑', '己',new double[]  {0.5,0.55, 0.53, 0.5, 0.55, 0.57, 0.6, 0.58, 0.5, 0.5, 0.57, 0.5}),


             new ZISTRENGTH('寅', '丙', new double[] {0.3,0.3, 0.36, 0.36, 0.318, 0.342, 0.36, 0.33, 0.3, 0.3, 0.342, 0.318}),


             new ZISTRENGTH('寅', '甲',new double[]  {0.84,0.742, 0.798, 0.84, 0.77, 0.7, 0.7, 0.728, 0.742, 0.7, 0.7, 0.84}),


             new ZISTRENGTH('卯', '乙', new double[] {1.2,1.06, 1.14, 1.2, 1.1, 1.0, 1.0, 1.04, 1.06, 1.0, 1.0, 1.2}),


             new ZISTRENGTH('辰', '乙',new double[]  {0.36,0.318, 0.342, 0.36, 0.33, 0.3, 0.3, 0.312, 0.318, 0.3, 0.3, 0.36}),


             new ZISTRENGTH('辰', '癸', new double[] {0.24,0.22,  0.2, 0.2, 0.208, 0.2, 0.2, 0.2,0.24, 0.24, 0.212, 0.228}),


             new ZISTRENGTH('辰', '戊',new double[]  {0.5,0.55, 0.53, 0.5, 0.55, 0.6, 0.6, 0.58, 0.5, 0.5, 0.57, 0.5}),


            new ZISTRENGTH('巳', '庚', new double[] {0.3,0.342, 0.3, 0.3, 0.33, 0.3, 0.3, 0.33, 0.342, 0.36, 0.348, 0.3}),


             new ZISTRENGTH('巳', '丙', new double[] {0.7,0.7, 0.84, 0.84, 0.742, 0.84, 0.84, 0.798, 0.7, 0.7, 0.728, 0.742}),


             new ZISTRENGTH('午', '丁', new double[] {1.0,1.0, 1.2, 1.2, 1.06, 1.14, 1.2, 1.1, 1.0, 1.0, 1.04, 1.06}),


             new ZISTRENGTH('未', '丁', new double[] {0.3,0.3, 0.36, 0.36, 0.318, 0.342, 0.36, 0.33, 0.3, 0.3, 0.312, 0.318}),


             new ZISTRENGTH('未', '乙',new double[]  {0.24,0.212, 0.228, 0.24, 0.22, 0.2, 0.2, 0.208, 0.212, 0.2, 0.2, 0.24}),


            new ZISTRENGTH('未', '己', new double[] {0.5,0.55, 0.53, 0.5, 0.55, 0.57, 0.6, 0.58, 0.5, 0.5, 0.57, 0.5}),


             new ZISTRENGTH('申', '壬', new double[] {0.36,0.33, 0.3, 0.3, 0.312, 0.318, 0.3, 0.3, 0.36, 0.36, 0.318, 0.342}),


             new ZISTRENGTH('申', '庚',new double[]  {0.7,0.798, 0.7, 0.7, 0.77, 0.742, 0.7, 0.77, 0.798, 0.84, 0.812, 0.7}),


             new ZISTRENGTH('酉', '辛',new double[]  {1.0,1.14, 1.0, 1.0, 1.1, 1.06, 1.0, 1.1, 1.14, 1.2, 1.16, 1.0}),


             new ZISTRENGTH('戌', '辛',new double[]  {0.3,0.342, 0.3, 0.3, 0.33, 0.318, 0.3, 0.33, 0.342, 0.36, 0.348, 0.3}),


             new ZISTRENGTH('戌', '丁', new double[] {0.2,0.2, 0.24, 0.24, 0.212, 0.228, 0.24, 0.22, 0.2, 0.2, 0.208, 0.212}),
             new ZISTRENGTH('戌', '戊',new double[]  {0.5,0.55, 0.53, 0.5, 0.55, 0.57, 0.6, 0.58, 0.5, 0.5, 0.57, 0.5}),
             new ZISTRENGTH('亥', '甲',new double[]  {0.36,0.318, 0.342, 0.36, 0.33, 0.3, 0.3, 0.312, 0.318, 0.3, 0.3, 0.36}),
             new ZISTRENGTH('亥', '壬',new double[]  {0.84,0.77, 0.7, 0.7, 0.728, 0.742, 0.7, 0.7, 0.84, 0.84, 0.724, 0.798})
            };
            
            /*
                     金 --- 0
                     木 --- 1
                     水 --- 2
                     火 --- 3
                     土 --- 4
            */




            char[] WuXingTable = new char[] { '金', '木', '水', '火', '土' };
            
            /*
                     天干地支的五行属性表
                     天干: 甲-木、乙-木、丙-火、丁-火、戊-土、己-土、庚-金、辛-金、壬-水、癸-水
                     地支:子-水、丑-土、寅-木、卯-木、辰-土、巳-火、午-火、未-土、申-金、酉-金、戌-土、亥-水
            */






            int[] TianGan_WuXingProp = new int[10] { 1, 1, 3, 3, 4, 4, 0, 0, 2, 2 };
            int[] DiZhi_WuXingProp = new int[12] { 2, 4, 1, 1, 4, 3, 3, 4, 0, 0, 4, 2 };
            int[] GenerationSourceTable = new int[5] { 4, 2, 0, 1, 3 };
            
            int ComputeGanIndex(char gan)
            {
                int i;


                for (i = 0; i < 10; i++)
                    if (TianGan[i] == gan) break;


                if (i >= 10) return -1;


                return i;
            }
            
            int ComputeZhiIndex(char zhi)
            {
                int i;


                for (i = 0; i < 12; i++)
                    if (DiZhi[i] == zhi) break;


                if (i >= 12) return -1;


                return i;
            }
            
            static string sResultBuf;   // 用作八字测算结果返回的字符缓冲区


            // 根据八字计算五行平衡
            // 输入参数:bazi,年月日时的干支,即俗称的八字
            // 输出结果:分析结果字符串,Unicode编码
            public string EvalBazi(string bazi)
            {
                double[] strengthResult = new double[5];


                int monthIndex = ComputeZhiIndex(bazi[3]);


                if (monthIndex == -1) return "";
                
                sResultBuf = bazi;
                sResultBuf += "\n\n五行强度:天干 + 支藏\n";


                for (int wuXing = 0; wuXing < 5; wuXing++)
                {
                    double value1 = 0.0, value2 = 0.0;
                    int i;


                    //扫描4个天干
                    for (i = 0; i < 8; i += 2)
                    {


                        char gan = bazi[i];


                        int index = ComputeGanIndex(gan);


                        if (index == -1) return "";
                        
                        if (TianGan_WuXingProp[index] == wuXing)
                            value1 += TianGan_Strength[monthIndex][index];
                    }
                    
                    //扫描支藏
                    for (i = 1; i < 8; i += 2)
                    {
                        char zhi = bazi[i];


                        for (int j = 0; j < DiZhi_Strength.Length; j++)
                        {


                            if (DiZhi_Strength[j].diZhi == zhi)
                            {


                                int zhiCangIndex = ComputeGanIndex(DiZhi_Strength[j].zhiCang);


                                if (zhiCangIndex == -1) return "";


                                if (TianGan_WuXingProp[zhiCangIndex] == wuXing)
                                {
                                    value2 += DiZhi_Strength[j].strength[monthIndex];
                                    break;
                                }
                            }
                        }
                    }


                    strengthResult[wuXing] = value1 + value2;
                    
                    //输出一行计算结果
                    {
                        string preStr;
                        string tmpBuf;


                        tmpBuf = value1.ToString("0.00") + " + " + value2.ToString("0.00") + " = " + (value1 + value2).ToString("0.00") + "\n";
                        
                        preStr = WuXingTable[wuXing] + ":\t";
                        sResultBuf += preStr;
                        sResultBuf += tmpBuf;
                    }
                }


                //根据日干求命里属性
                int fateProp, srcProp;
                {
                    string tmpWBuf;


                    fateProp = TianGan_WuXingProp[ComputeGanIndex(bazi[4])];


                    if (fateProp == -1) return "";
                    
                    tmpWBuf = "\n命属" + WuXingTable[fateProp] + "\n\n";
                    sResultBuf += tmpWBuf;
                }


                //求同类和异类的强度值
                srcProp = GenerationSourceTable[fateProp];
                {
                    string preStr;
                    string tmpBuf;
                    double tongLei = strengthResult[fateProp] + strengthResult[srcProp];
                    double yiLei = 0.0;


                    for (int i = 0; i < 5; i++) yiLei += strengthResult[i];


                    yiLei -= tongLei;
                    
                    tmpBuf = strengthResult[fateProp].ToString("0.00") + " + " + strengthResult[srcProp].ToString("0.00") + " = " + tongLei.ToString("0.00") + "\n";
                    preStr = "同类:" + WuXingTable[fateProp] + "+" + WuXingTable[srcProp] + ",";


                    sResultBuf += preStr;
                    sResultBuf += tmpBuf;


                    tmpBuf = yiLei.ToString("0.00") + "\n";
                    sResultBuf += "异类:总和为 " + tmpBuf;
                }
                return sResultBuf;
            }
        }


    注:原作c代码里面对于hour小时的范围有个前后矛盾,这里加了一句if (hour > 22) hour -= 24;来匹配范围。


    这个方法需要先去比如nongli.net查询八字的前6字,也就是年月子对应的天干和地支,这个查万年历当然是很容易的,不过也可以用代码的形式输入年月日就自动得到这前6字,然后调用本篇的代码算出五行。至于得到前6字的算法大家可以研究nongli.net的js代码然后改写成C#代码,这个大家可以自己尝试哈。能做到自动生成的话,其实本篇的CheckBazi()函数就不需要了。

    值得一提的是,本篇的c语言转成c#还是简单的,其实js转成c#也是简单的,不过有些时间函数C#并没有一一对应的,这里讲解两个关键的。

    在JS里面的Date.UTC(1900,0,6,2,5)这个函数在C#是没有对应的,所以需要自己写,需要注意的是此函数的月份范围是0~11而不是1-12,所以在用C#的datetime来表示的时候,月份需要+1,另外就是时区的问题,中国在东8区,所以正常情况下你的电脑设置的时区也是东8区的北京时间的话,在做转换的时候需要考虑这个问题。UTC返回的可以用double变量来存,用int是不够的切记。

    还有new Date( Date.UTC(1900,0,6,2,5) )这个函数会把计算的UTC数值再转化成日期并取出天的数值,需要写另外一个C#函数来实现,下面是代码。

    public double ConvertDateTimeInt(System.DateTime time)
            {
                double intResult = 0;
                System.DateTime startTime = TimeZone.CurrentTimeZone.ToLocalTime(new System.DateTime(1970, 1, 1));
                time = time.AddHours(8);//转化为北京时间(北京时间=UTC时间+8小时 )
                intResult = (time - startTime).TotalMilliseconds;
                return intResult;
            }
            public DateTime ConvertIntDatetime(double utc)
            {
                System.DateTime startTime = TimeZone.CurrentTimeZone.ToLocalTime(new System.DateTime(1970, 1, 1));
                startTime = startTime.AddMilliseconds(utc);
                startTime = startTime.AddHours(-8);//转化为北京时间(北京时间=UTC时间+8小时 )
                return startTime;
            }

    这里面的addHours的8和-8都是实际测试验证的。有了上面2个函数,要计算八字就不难了。


    展开全文
  • Python 实现一输入多个数字(用空格隔开)很多人都会使用以下代码,来实现多个字符串的连续输入,但是这是以换行进行操作的,而有些题目需要将一些数字进行一输入a=input()b=input()1.实现一输入多个数字,并以...

    Python 实现一行输入多个数字(用空格隔开)

    很多人都会使用以下代码,来实现多个字符串的连续输入,但是这是以换行进行操作的,而有些题目需要将一些数字进行一行输入

    a=input()

    b=input()

    1.实现一行输入多个数字,并以空格隔开。

    a,b=map(int,input().split())

    print(a,b)

    print(type(a))

    #运行结果

    1 2

    1 2

    2.实现一个输入多个单词,每个单词之间用逗号隔开。

    str1,str2=map(str,input().split(','))

    print(str1,str2)

    print(type(str1))

    #运行结果

    love,china

    love china

    例题:将二进制日期翻译为十进制的形式并输出。例如,日期 00010 00000 00010 00000 00001 00011,翻译为2020年1月3日。int(x,2):将一个二进制的数字准换为十进制。

    print("请输入报道日期,每位二进制数之间用空格隔开")

    sstr=""

    year1,year2,year3,year4,month,day=map(str,input().split())

    sstr=sstr+str(int(year1,2))+str(int(year2,2))+str(int(year3,2))+str(int(year4,2))+"年"

    sstr=sstr+str(int(month,2))+"月"

    sstr=sstr+str(int(day,2))+"日"

    print(sstr)

    #运行结果

    请输入报道日期,每位二进制数之间用空格隔开

    00010 00000 00001 00100 00100 00001

    2014年4月1日

    到此这篇关于Python 实现一行输入多个数字(用空格隔开)的文章就介绍到这了,更多相关Python一行输入多个数字内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

    时间: 2020-04-28

    注:以下内容在python3中操作 一. 一行输入多个值 a,b = input().split() #此时得到的a和b的类型均为字符串,以空格为分隔符 a,b = input().split(',') #此时得到的a和b的类型均为字符串,以逗号为分隔符 具体操作如下: a,b = map(int,input( ).split( )) #此时得到的a和b的类型为整数,以空格为分隔符 具体操作如下: 补充split( ): 语法:str.split(str = ' ',num)[n] 其中str:

    在使用python去AC题时总会遇到这样的问题,题目要求同行输入一组数据,但是你使用input时却不能做到,导致不断的CE,这个时候怎么样来解决的这个问题呢? 很简单,只需要使用input().split(' ')就可以了 例如:最简单的求a+b的例子,写成下面的形式就可以单行输入两个数据了 a , b = input ().split(' ') #以空格为间隔符 print (a+b) 结果如下: 注意input的输入机制,他是把所有输入都按照字符串输入的所以这样输出的a+b是按字符串形式直接

    如下所示: stopword = '' str = '' for line in iter(raw_input, stopword): str += line + '\n' print(str) 以上这篇用python 实现在不确定行数情况下多行输入方法就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持我们.

    python3的输入方式 1. 读取键盘输入 内置函数 input()接收键盘标准输入 str = input("请输入") print(str) 默认返回的是字符串类型,通过强制转换可以变成其他类型 num = int(input("请输入")) print(num, type(num)) //type(变量),返回变量类型 2. raw_input()(只适用python2) input() 函数和raw_input() 函数基本可以互换,但是input会假设你

    python如何实现一行输入多个值呢? 例如 读入两个数10 23到a b  中. 很简单   a,b = input().split()  即可. 当然,a,b中保存的是字符串. 如果要求a,b中保存的是整数的话可以这样写 a,b = map(int,input().split()) 以上这篇Python 实现一行输入多个值的方法就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持我们. 您可能感兴趣的文章: python实现同时给多个变量赋值的方法 python实现在ID

    Python中输入多行字符串: 方法一:使用三引号 >>> str1 = '''Le vent se lève, il faut tenter de vivre. 起风了,唯有努力生存. (纵有疾风起,人生不言弃.)''' >>> str1 'Le vent se lève, il faut tenter de vivre. \n起风了,唯有努力生存.\n(纵有疾风起,人生不言弃.)' >>> print(str1) Le vent se lève,

    先给大家介绍下python交互模式下输入换行/输入多行命令的方法 换行方法 \ 如: >>> print 'aaa'; \  ... print 'bbb'; \  ... print 'ccc' 注意;号的使用. python本身语句结束和间隔都是不需要:号的,但是在换行时要使用:号,最后一行不要求必须有:号,加上也不会出错. ps:下面看下如何在python的交互式命令行下换行 >>> 是python的输入提示符,回车则输入结束.那么如何输入两条以上的语句呢 换行方

    学习了Python相关数据类型,函数的知识后,利用字符串的分割实现了输入任意多个数据,并计算其平均值的小程序.思路是接收输入的字符串,以空格为分隔符,将分割的数据存入列表(lst1)中,将lst1中的数据转存入另一个空列表(lst)中,转存时将字符串转化为整型,从而利用函数求出lst中数的和.平均值,是Python基础(5)中结尾程序的升级版. 代码如下: print("-----求平均值,可输入任意多个数-------") lst = [] #定义一个空列表 str = raw_in

    L3Byb3h5L2h0dHAvZmlsZXMuamI1MS5uZXQvZmlsZV9pbWFnZXMvYXJ0aWNsZS8yMDE5MTAvMjAxOTEwMjcxMTM4NTMyMTYucG5nJiMwNjM7MjAxOTkyNzExMzkz.jpg

    输入任意一个大写字母,生成金字塔图形 def GoldTa(input): L = [chr(i) for i in range(65, 91)] # 大写字母A--Z idA = 65 # 从A开始 # ord()函数将字母转换为Unicode数值 idInput = ord(input) num = idInput - idA + 1 # 输入的字符个数 tempResult = "" for C in range(0, num): for C1 in range(0, C): #

    有时候,预先不知道函数需要接受多少个实参,好在Python允许函数从调用语句中调用语句中收集任意数量的实参.在参数前加上*号. 来看一个制作披萨的函数,它需要接受很多配料,但你无法预先确定顾客要多少种配料.下面的函数只有一个形参*toppings,但不管调用语句提供了多少实参,这个形参都将他们统统收入囊中: def make_pizza(*toppings): """打印顾客点的所有配料""" print(toppings) make_pizza

    这个功能倒也不是我多么急需的功能,只是恰好看到了,觉得或许以后会用的到.功能就是实现函数能够接受不同数目的参数. 其实,在C语言中这个功能是熟悉的,虽说实现的形式不太一样.C语言中的main函数是可以实现类似的功能的,可以通过这种方式实现一个支持命令行参数的程序. 先写一段python实现相应功能的示范代码: defFuncDemo(*par): print("number of pars: %d" %len(par)) print("type of par: %s&quot

    python自定义函数在运行时,最初只是存在内存中,只有调用时才会触发运行. def cube_count(a): if is_number(a): return a**3 else: print("非数字不能计算立方值") def is_number(a): if not isinstance(a,(int,float)): print("输入的%s不是数字,请重新输入"%a) return False else: return True c = cube_cou

    前言 要实现该功能,需要的就是暂停程序.等待并捕捉用户的一个键盘输入,然后继续执行.Python 有内建的库能帮我们实现该功能,不过要区别对待 Windows 和 Linux. msvcrt 中的 getch() 方法 能够帮助在 Windows 下实现,其作用是获取一个按键响应并返回对应的字符.它并不在命令行中回显.有如下程序段: import msvcrt print ord(msvcrt.getch()) 这里利用 ord 将获得的字符转换为 ASCII 数值,例如捕获按键"d"

    某天在群内有同学问到,在python下我用input或者raw_input都得输入完后回车才能获取到输入的值,那如何实现任意键退出暂停等功能呢,我当时也没有多想,因为接触python时间也不算长,主要还是Linux下的. 当然,Windows系统下会稍微简单一些,Windows系统下如果你安装了python的环境,默认自带的一个模块叫做msvcrt,import msvcrt,然后调用msvcrt.getch()即可.接下来即Linux下实现python版本的按任意键退出. 初学Python时在

    本文实例讲述了Python实现的对一个数进行因式分解操作.分享给大家供大家参考,具体如下: 在数学中,我们可能会对一个数进行因式分解,如何用Python来实现呢?以下是某位大佬写的算法,这里拿过来直接用就可以了. # 对一个数进行因式分解 def factorization(num): factor = [] while num > 1: for i in range(num - 1): k = i + 2 if num % k == 0: factor.append(k) num = int(

    如下所示: # -*- coding: utf-8 -*- # 水仙花数是指一个 n 位正整数 ( n≥3 ),它的每个位上的数字的 n 次幂之和等于它本身. # 要求:打印输出所有的"水仙花数". def f(n): list=[] for i in range(pow(10,n-1),pow(10,n)): list=map(int,str(i)) sum = 0 for k in range(0,len(list)): sum=sum+pow(list[k],n) if sum=

    不用库,写了很久,一直出bug,到网上一搜,可以直接输入之后,eval(str)即可得到结果! eval程序如下: s=input("请输入要运算的数字") print("The result is{}".format(eval(s))) 下面是不用eval实现加减的代码:主要思想就是通过一个标志位flag来计算是否进行加减,其他的都很好理解 s=input("请输入要运算的数字") l=len(s) h=0 i=0 flag=1 a=0 for

    展开全文
  • 重写 AOF持久化是保存了一堆命令来恢复数据库,随着时间流逝,的会越来越多,如果不加以控制,文件过大可能影响服务器甚至计算机。而且文件过大,恢复时需要时间也太长。 所以redis提供了重写功能,写出的新文件...

    后端需要知道的关于redis的事,基本都在这里了。

    此文后续会改为粉丝可见,所以喜欢的请提前关注。

    你的点赞和评论是我创作的最大动力,谢谢。

    3、单机实现

    3.1、数据库概述

    redis服务器将所有数据库都保存在redis/redisServer中,数组db存放所有数据库,每一项是一个redisdb结构。dbnum代表数据库数量。

    客户端有一个指针指向当前数据库,可以切换,也就是移动指针。

    3.1.1键空间

    现在稍微介绍一下redisdb结构,它的字典保存了所有键值对

    键空间的键也就是数据库的键, 每个键都是一个字符串对象。

    键空间的值也就是数据库的值, 每个值可以是字符串对象、列表对象、哈希表对象、集合对象、有序集合对象

    所有数据库的操作,添加一个键值对, 删除一个键值对, 获取某个键值对, 等等,都是通过对键空间字典进行操作来实现的。

    3.1.2维护

    读写键空间的时候,服务器会执行一些额外操作,比如:

    • 读一个键后(读操作写操作都要对键读取), 会根据键是否存在, 更新键空间命中(hit)次数或不命中(miss)次数。
    • 读取一个键后, 服务器会更新键的 LRU (最后一次使用)时间, 这个值可以用于计算键的闲置时间。
    • 如果服务器在读一个键时, 该键已经过期, 服务器会删除这个键, 然后执行其他操作。
    • 如果客户使用 WATCH 监视某个键,在对这个键进行修改之后, 会将这个键记为脏(dirty),让事务程序知到这个键被修改
    • 服务器每次修改一个键之后, 都会对脏(dirty)键计数器的值增一, 这个计数器会触发服务器的持久化以及复制操作执行
    • 如果服务器开启了数据库通知功能, 那么在对键进行修改之后, 服务器将按配置发送相应的数据库通知。

    3.1.3时间

    用户可以给某个键设置生存时间,过期时间是一个UNIX时间戳,到时间自动删除这个键。

    redisdb结构的expires字典保存了所有的键的过期时间,我们称这个字典为过期字典。

    3.1.4三种过期键删除策略

    1)定时删除:创建一个定时器,到时间立即执行删除操作(对内存友好,因为能保证过期了立马删除,但是对cpu不友好)

    2)惰性删除:键过期不管,每次获取键时检查是否过期,过期就删除(对cpu友好,但是只有在使用的时候才可能删除,对内存不友好)

    3)定期删除:隔一段时间检查一次(具体算法决定检查多少删多少,需要合理设置)

    3.1.5淘汰策略

    当Redis占用内存超出最大限制 (maxmemory) 时,可采用如下策略 (maxmemory-policy) ,让Redis淘汰一些数据,以腾出空间继续提供读写服务 :

    noeviction: 对可能导致增大内存的命令返回错误 (大多数写命令,DEL除外) ;

    volatile-ttl: 在设置了过期时间的key中,选择剩余寿命 (TTL) 最短的key,将其淘汰;

    volatile-lru: 在设置了过期时间的key中,选择最少使用的key (RU) ,将其淘汰;

    volatile-random: 在设置了过期时间的key中,随机选择一些key,将其淘汰;

    allkeys-1Lru: 在所有的key中,选择最少使用的key (LRU) ,将其淘汰;

    allkeys-random: 在所有的key中,随机选择一些key,将其淘汰;

     

    3.2、持久化

    因为redis是内存数据库,他把数据都存在内存里,所以要想办法实现持久化功能。

    3.2.1、RDB

    RDB持久化可以手动执行,也可以配置定期执行,可以把某个时间的数据状态保存到RDB文件中,反之,我们可以用RDB文件还原数据库状态。

        生成

    有两个命令可以生成RDB文件:

    • SAVE 命令由服务器进程直接执行保存操作,所以该命令会阻塞服务器,服务器不能接受其他指令。
    • BGSAVE 命令由子进程执行保存操作,所以该命令不会阻塞服务器,服务器可以接受其他指令。。

    禁止BGSAVE和SAVE同时执行,也就是说执行其中一个就会拒绝另一个,这是为了避免父进程和子进程同时执行两个rdbsave,防止产生竞争条件。

        载入

        RDB载入工作是服务器启动时自动执行的。

        自动保存

    用户可以通过save选项设置多个保存条件,服务器状态中会保存所有用 save 选项设置的保存条件,当任意一个保存条件被满足时,服务器会自动执行 BGSAVE 命令。

    比如

    save 900 1

    save 300 10

    满足:服务器在900秒之内被修改至少一次或者300秒内修改至少十次。就会执行BGSAVE。

     

    当服务器启动时,用户可以通过指定配置文件或者传入启动参数来设置save选项,服务器会把条件放到一个结构体里,结构体有一个数组,保存了所有条件。

     

    serverCron函数默认100毫秒检查一次,他会遍历数组依次检查,符合条件就会执行BGSAVE。

        RDB文件结构

    一个完整 RDB 文件所包含的各个部分:

    REDIS,长度5字节, 保存着 "REDIS" 五个字符。 通过这五个字符, 可以在载入文件时, 快速检查载入文件是否 RDB 文件。

    db_version ,长度 4 字节, 它的值是一个字符串表示的整数, 这个整数记录了 RDB 文件的版本号

    databases 部分包含着零个或任意多个数据库, 以及各个数据库中的键值对数据

    EOF 常量的长度为 1 字节, 这个常量标志着 RDB 文件正文内容的结束

    check_sum 是一个 8 字节长的无符号整数, 保存着一个校验和,以此来检查 RDB 文件是否出错或损坏

    我并不想深入探究databases的组成。就是知道

    • RDB 文件是一个经过压缩的二进制文件,由多个部分组成。
    • 对于不同类型的键值对, RDB 文件会使用不同的方式来保存它们即可。

    3.2.2、AOF

    AOF持久化是通过保存服务器执行的命令来记录状态的。还原的时候再执行一遍即可。

    功能的实现可以分为命令追加、文件写入、文件同步三个步骤。

     

    当 AOF 持久化功能处于打开状态时, 服务器在执行完一个写命令之后, 会以协议格式将被执行的写命令追加到服务器状态的 aof_buf 缓冲区的末尾:

    struct redisServer {
        // ...
        // AOF 缓冲区
        sds aof_buf;
        // ...
    };

    Redis 服务器进程就是一个事件循环

    循环中的文件事件负责接收客户端的命令请求, 以及向客户端发送命令回复,

    而时间事件则负责执行像 serverCron 函数这样需要定时运行的函数。

    因为服务器在处理文件事件时可能会执行写命令, 使得一些内容被追加到 aof_buf 缓冲区里面, 所以在服务器每次结束一个事件循环之前, 它都会调用 flushAppendOnlyFile 函数, 考虑是否需要将 aof_buf 缓冲区中的内容写入和保存到 AOF 文件里面, 这个过程可以用伪代码表示:

    def eventLoop():
    
        while True:
    
            # 处理文件事件,接收命令请求以及发送命令回复
            # 处理命令请求时可能会有新内容被追加到 aof_buf 缓冲区中
            processFileEvents()
    
            # 处理时间事件
            processTimeEvents()
    
            # 考虑是否要将 aof_buf 中的内容写入和保存到 AOF 文件里面
            flushAppendOnlyFile()

    flushAppendOnlyFile 函数的行为由服务器配置的 appendfsync 选项的值来决定

    值为 always 时, 服务器在每个事件循环都要将 aof_buf 缓冲区中的所有内容写入到 AOF 文件并且同步 AOF 文件, 所以 always 的效率最慢的一个, 但从安全性来说, always 是最安全的, 因为即使出现故障停机, AOF 持久化也只会丢失一个事件循环中所产生的命令数据。

    值为 everysec 时, 服务器在每个事件循环都要将 aof_buf 缓冲区中的所有内容写入到 AOF 文件, 每隔超过一秒就要在子线程中对 AOF 文件进行一次同步: 从效率上来讲, everysec 模式足够快, 并且就算出现故障停机, 数据库也只丢失一秒钟的命令数据。

    值为 no 时, 服务器在每个事件循环都要将 aof_buf 缓冲区中的所有内容写入到 AOF 文件, 至于何时对 AOF 文件进行同步, 则由操作系统控制。

    因为处于 no 模式下的 flushAppendOnlyFile 调用无须执行同步操作, 所以该模式下的 AOF 文件写入速度总是最快的, 不过因为这种模式会在系统缓存中积累一段时间的写入数据, 所以该模式的单次同步时长通常是三种模式中时间最长的: 从平摊操作的角度来看,no 模式和 everysec 模式的效率类似, 当出现故障停机时, 使用 no 模式的服务器将丢失上次同步 AOF 文件之后的所有写命令数据。

        重写

    AOF持久化是保存了一堆命令来恢复数据库,随着时间流逝,存的会越来越多,如果不加以控制,文件过大可能影响服务器甚至计算机。而且文件过大,恢复时需要时间也太长。

    所以redis提供了重写功能,写出的新文件不会包含任何浪费时间的冗余命令。

    接下来,我们就介绍重写的原理。

    其实重写不会对现有的AOF文件进行读取分析等操作,而是通过当前服务器的状态来实现。

     # 假设服务器对键list执行了以下命令s;
    127.0.0.1:6379> RPUSH list "A" "B"
    (integer) 2
    127.0.0.1:6379> RPUSH list "C"
    (integer) 3
    127.0.0.1:6379> RPUSH list "D" "E"
    (integer) 5
    127.0.0.1:6379> LPOP list
    "A"
    127.0.0.1:6379> LPOP list
    "B"
    127.0.0.1:6379> RPUSH list "F" "G"
    (integer) 5
    127.0.0.1:6379> LRANGE list 0 -1
    1) "C"
    2) "D"
    3) "E"
    4) "F"
    5) "G"
    127.0.0.1:6379> 

    当前列表键list在数据库中的值就为["C", "D", "E", "F", "G"]。要使用尽量少的命令来记录list键的状态,最简单的方式不是去读取和分析现有AOF文件的内容,,而是直接读取list键在数据库中的当前值,然后用一条RPUSH list "C" "D" "E" "F" "G"代替前面的6条命令。

    • 伪代码表示如下
    def AOF_REWRITE(tmp_tile_name):
    
      f = create(tmp_tile_name)
    
      # 遍历所有数据库
      for db in redisServer.db:
    
        # 如果数据库为空,那么跳过这个数据库
        if db.is_empty(): continue
    
        # 写入 SELECT 命令,用于切换数据库
        f.write_command("SELECT " + db.number)
    
        # 遍历所有键
        for key in db:
    
          # 如果键带有过期时间,并且已经过期,那么跳过这个键
          if key.have_expire_time() and key.is_expired(): continue
    
          if key.type == String:
    
            # 用 SET key value 命令来保存字符串键
    
            value = get_value_from_string(key)
    
            f.write_command("SET " + key + value)
    
          elif key.type == List:
    
            # 用 RPUSH key item1 item2 ... itemN 命令来保存列表键
    
            item1, item2, ..., itemN = get_item_from_list(key)
    
            f.write_command("RPUSH " + key + item1 + item2 + ... + itemN)
    
          elif key.type == Set:
    
            # 用 SADD key member1 member2 ... memberN 命令来保存集合键
    
            member1, member2, ..., memberN = get_member_from_set(key)
    
            f.write_command("SADD " + key + member1 + member2 + ... + memberN)
    
          elif key.type == Hash:
    
            # 用 HMSET key field1 value1 field2 value2 ... fieldN valueN 命令来保存哈希键
    
            field1, value1, field2, value2, ..., fieldN, valueN =\
            get_field_and_value_from_hash(key)
    
            f.write_command("HMSET " + key + field1 + value1 + field2 + value2 +\
                            ... + fieldN + valueN)
    
          elif key.type == SortedSet:
    
            # 用 ZADD key score1 member1 score2 member2 ... scoreN memberN
            # 命令来保存有序集键
    
            score1, member1, score2, member2, ..., scoreN, memberN = \
            get_score_and_member_from_sorted_set(key)
    
            f.write_command("ZADD " + key + score1 + member1 + score2 + member2 +\
                            ... + scoreN + memberN)
    
          else:
    
            raise_type_error()
    
          # 如果键带有过期时间,那么用 EXPIREAT key time 命令来保存键的过期时间
          if key.have_expire_time():
            f.write_command("EXPIREAT " + key + key.expire_time_in_unix_timestamp())
    
        # 关闭文件
        f.close()

        AOF后台重写


    aof_rewrite函数可以创建新的AOF文件,但是这个函数会进行大量的写入操作,所以调用这个函数的线程被长时间的阻塞,因为服务器使用单线程来处理命令请求;所以如果直接是服务器进程调用AOF_REWRITE函数的话,那么重写AOF期间,服务器将无法处理客户端发送来的命令请求;


    Redis不希望AOF重写会造成服务器无法处理请求,所以将AOF重写程序放到子进程(后台)里执行。这样处理的好处是: 
    1)子进程进行AOF重写期间,主进程可以继续处理命令请求;
    2)子进程带有主进程的数据副本,使用子进程而不是线程,可以避免在锁的情况下,保证数据的安全性。

    还有一个问题,可能重写的时候又有新的命令过来,造成信息不对等,所以redis设置了一个缓冲区,重写期间把命令放到重写缓冲区。
     

      总结
    AOF重写的目的是为了解决AOF文件体积膨胀的问题,使用更小的体积来保存数据库状态,整个重写过程基本上不影响Redis主进程处理命令请求;
    AOF重写其实是一个有歧义的名字,实际上重写工作是针对数据库的当前状态来进行的,重写过程中不会读写、也不适用原来的AOF文件;
    AOF可以由用户手动触发,也可以由服务器自动触发。

     

    3.3、事件

    redis服务器是一个事件驱动程序。

    需要处理两类事件:

    1)文件事件:redis是通过套接字与客户端或者其他服务器连接的,而文件事件就是服务器对套接字操作的抽象。

    2)时间事件:服务器对一些定时操作的抽象。

    3.3.1、文件事件

    redis基于reactor模式开发了自己的网络事件处理器,这个处理器被称作文件事件处理器,它使用IO多路复用程序来同时监听多个套接字, 并根据套接字目前执行的任务来为套接字关联不同的事件处理器,当被监听的套接字准备好执行连接应答(accept)、读取(read)、写入(write)、关闭(close)等操作时, 与操作相对应的文件事件就会产生, 这时文件事件处理器就会调用套接字之前关联好的事件处理器来处理这些事件。

    虽然文件事件处理器以单线程方式运行, 但通过使用 I/O 多路复用程序来监听多个套接字, 文件事件处理器既实现了高性能的网络通信模型, 又可以很好地与 Redis 服务器中其他同样以单线程方式运行的模块进行对接, 这保持了 Redis 内部单线程设计的简单性。

    文件事件处理器的构成:

    I/O 多路复用程序负责监听多个套接字, 并向文件事件分派器传送那些产生了事件的套接字。

     I/O 多路复用程序会把所有产生事件的套接字放到一个队列, 以有序(sequentially)、同步(synchronously)、每次一个套接字的方式,向文件事件分派器传送套接字。

    I/O 多路复用程序可以监听多个套接字的 ae.h/AE_READABLE 事件和 ae.h/AE_WRITABLE 事件

    1)当套接字变得可读时(客户端对套接字执行 write 操作,或者执行 close 操作), 或者有新的可应答(acceptable)套接字出现时(客户端对服务器的监听套接字执行 connect 操作), 套接字产生 AE_READABLE 事件。

    2)当套接字变得可写时(客户端对套接字执行 read 操作), 套接字产生 AE_WRITABLE 事件。

    如果一个套接字又可读又可写的话, 那么服务器将先读套接字, 后写套接字。

    下面介绍各种处理器:

    1)连接应答处理器:服务器进行初始化时, 程序会将连接应答处理器和服务器监听套接字的 AE_READABLE 事件关联, 当有客户端连接(connect)服务器监听套接字的时候, 套接字就会产生 AE_READABLE 事件, 引发连接应答处理器执行, 并执行相应的套接字应答操作。

    2)命令请求处理器:客户端连接到服务器后, 服务器会将客户端套接字的 AE_READABLE 事件和命令请求处理器关联起来, 当客户端发送命令请求时, 套接字就会产生 AE_READABLE 事件, 引发命令请求处理器执行, 并执行相应的套接字读入操作

    3)命令回复处理器:服务器有命令回复需要传送给客户端, 服务器会将客户端套接字的 AE_WRITABLE 事件和命令回复处理器关联起来, 当客户端准备好接收服务器传回的命令回复时, 就会产生 AE_WRITABLE 事件, 引发命令回复处理器执行, 并执行相应的套接字写入操作。

    一次完整的连接事件实例:

    3.3.2、时间事件

    redis时间事件可以分为两类:定时事件、周期性事件,他们的特点就像他们的名字一样。

    而一个时间事件主要有三部分:

    id:服务器为时间事件创建的全局唯一id,按时间递增,越新的越大

    when:unix时间戳,记录到达时间

    timeProc:时间事件处理器,是一个函数,时间事件到达时,服务器就会调用处理器来处理事件。

    目前版本的redis只使用周期性事件

    来看看实现:

    服务器把所有时间事件放在一个链表中,每当时间事件执行器执行时,它就遍历链表,调用相应的事件处理器。

    但是注意:链表是无序的,不按when属性来排序,当时间事件执行器运行时,必须遍历整个链表。但是,无序链表并不影响时间事件处理器的性能,因为在目前版本中,redis服务器只使用serverCron一个时间事件,就算在benchmark模式下也只有两个事件,服务器几乎是把链表退化成指针使用了。

     

    3.3.3、事件的调度和执行

     

    文件事件和时间事件之间是合作关系, 服务器会轮流处理这两种事件,对两种事件的处理都是同步、有序、原子地进行的,处理事件的过程中也不会进行抢占,所以时间事件的实际处理时间通常会比设定的到达时间晚一些

    大概流程为:

    是否关闭服务器?---->等待文件事件产生---->处理已经产生的文件事件---->处理已经达到的时间事件---->是否关闭服务器?........

     

    3.4、客户端

    redis服务器是典型的一对多服务器,通过使用由IO多路复用技术实现的文件事件处理器,redis服务器使用了单线程单进程的方式来处理请求。

    3.4.1客户端的属性

    • 描述符

    客户端状态的 fd 属性记录了客户端正在使用的套接字描述符:

    typedef struct redisClient {
        // ...
    
        int fd;
    
        // ...
    } redisClient;
    • 伪客户端fd 值为 -1 : 伪客户端处理的命令请求来源于 AOF 文件或者 Lua 脚本, 而不是网络, 所以这种客户端不需要套接字连接。
    • 普通客户端 fd 值为大于 -1 的整数: 普通客户端使用套接字来与服务器进行通讯, 所以服务器会用 fd 属性来记录客户端套接字的描述符。 

     

    • 标志

    客户端的标志属性 flags 记录了客户端的角色(role), 以及客户端目前所处的状态:

    typedef struct redisClient {
        // ...
    
        int flags;
    
        // ...
    
    } redisClient;

    flags 属性的值可以是单个标志:

    flags = <flag>
    

    也可以是多个标志的二进制或, 比如:

    flags = <flag1> | <flag2> | ...
    

    每个标志使用一个常量表示, 一部分标志记录了客户端的角色:

    • 在主从服务器进行复制操作时, 主服务器会成为从服务器的客户端, 而从服务器也会成为主服务器的客户端。 REDIS_MASTER 标志表示客户端代表的是一个主服务器, REDIS_SLAVE 标志表示客户端代表的是一个从服务器。
    • REDIS_LUA_CLIENT 标识表示客户端是专门用于处理 Lua 脚本里面包含的 Redis 命令的伪客户端。

    另一部分标志记录了客户端目前所处的状态:

    以下内容为摘抄
    REDIS_MONITOR 标志表示客户端正在执行 MONITOR 命令。
    
    REDIS_UNIX_SOCKET 标志表示服务器使用 UNIX 套接字来连接客户端。
    
    REDIS_BLOCKED 标志表示客户端正在被 BRPOP 、 BLPOP 等命令阻塞。
    
    REDIS_UNBLOCKED 标志表示客户端已经从 REDIS_BLOCKED 标志所表示的阻塞状态中脱离出来, 
    不再阻塞。 REDIS_UNBLOCKED 标志只能在 REDIS_BLOCKED 标志已经打开的情况下使用。
    
    REDIS_MULTI 标志表示客户端正在执行事务。
    
    REDIS_DIRTY_CAS 标志表示事务使用 WATCH 命令监视的数据库键已经被修改, 
    REDIS_DIRTY_EXEC 标志表示事务在命令入队时出现了错误, 
    以上两个标志都表示事务的安全性已经被破坏, 只要这两个标记中的任意一个被打开, 
    EXEC 命令必然会执行失败。 
    这两个标志只能在客户端打开了 REDIS_MULTI 标志的情况下使用。
    
    REDIS_CLOSE_ASAP 标志表示客户端的输出缓冲区大小超出了服务器允许的范围, 
    服务器会在下一次执行 serverCron 函数时关闭这个客户端, 
    以免服务器的稳定性受到这个客户端影响。 
    积存在输出缓冲区中的所有内容会直接被释放, 不会返回给客户端。
    
    REDIS_CLOSE_AFTER_REPLY 标志表示有用户对这个客户端执行了 CLIENT_KILL 命令, 
    或者客户端发送给服务器的命令请求中包含了错误的协议内容。 
    服务器会将客户端积存在输出缓冲区中的所有内容发送给客户端, 然后关闭客户端。
    
    REDIS_ASKING 标志表示客户端向集群节点(运行在集群模式下的服务器)发送了 ASKING 命令。
    
    REDIS_FORCE_AOF 标志强制服务器将当前执行的命令写入到 AOF 文件里面,
    REDIS_FORCE_REPL 标志强制主服务器将当前执行的命令复制给所有从服务器。 
    执行 PUBSUB 命令会使客户端打开 REDIS_FORCE_AOF 标志, 
    执行 SCRIPT_LOAD 命令会使客户端打开 
    REDIS_FORCE_AOF标志和 REDIS_FORCE_REPL 标志。
    
    在主从服务器进行命令传播期间, 从服务器需要向主服务器发送 REPLICATION ACK 命令, 
    在发送这个命令之前, 从服务器必须打开主服务器对应的客户端的 
    REDIS_MASTER_FORCE_REPLY 标志, 否则发送操作会被拒绝执行。

    以上提到的所有标志都定义在 redis.h 文件里面。

    PUBSUB 命令和 SCRIPT LOAD 命令的特殊性

    通常情况下, Redis 只会将那些对数据库进行了修改的命令写入到 AOF 文件, 并复制到各个从服务器: 如果一个命令没有对数据库进行任何修改, 那么它就会被认为是只读命令, 这个命令不会被写入到 AOF 文件, 也不会被复制到从服务器。

    以上规则适用于绝大部分 Redis 命令, 但 PUBSUB 命令和 SCRIPT_LOAD 命令是其中的例外。

    PUBSUB 命令虽然没有修改数据库, 但 PUBSUB 命令向频道的所有订阅者发送消息这一行为带有副作用, 接收到消息的所有客户端的状态都会因为这个命令而改变。 因此, 服务器需要使用 REDIS_FORCE_AOF 标志, 强制将这个命令写入 AOF 文件, 这样在将来载入 AOF 文件时, 服务器就可以再次执行相同的 PUBSUB 命令, 并产生相同的副作用。

    SCRIPT_LOAD 命令的与 PUBSUB 命令类似

    3.4.2输入缓冲区

    客户端状态的输入缓冲区用于保存客户端发送的命令请求:

    typedef struct redisClient {
    
        // ...
    
        sds querybuf;
    
        // ...
    
    } redisClient;

     redisClient 实例:

    3.4.3命令相关

    在服务器将客户端发送的命令请求保存到客户端状态的 querybuf 属性之后, 服务器将对命令请求的内容进行分析, 并将得出的命令参数以及命令参数的个数分别保存到客户端状态的 argv 属性和 argc 属性:

    typedef struct redisClient {
    
        // ...
    
        robj **argv;
    
        int argc;
    
        // ...
    
    } redisClient;

    argv 属性是一个数组, 数组中的每个项都是一个字符串对象: 其中 argv[0] 是要执行的命令, 而之后的其他项则是传给命令的参数。

    argc 属性则负责记录 argv 数组的长度。

    3.3.4实现函数

     

    当服务器从协议内容中分析并得出 argv 属性和 argc 属性的值之后, 服务器将根据项 argv[0] 的值, 在命令表中查找命令所对应的命令实现函数。

    (命令表是一个字典,字典的键是一个 SDS 结构, 保存了命令的名字, 字典的值是命令所对应的 redisCommand 结构, 这个结构保存了命令的实现函数、 命令的标志、 命令应该给定的参数个数、 命令的总执行次数和总消耗时长等统计信息。)

    3.3.5、输出缓冲区

    执行命令所得的命令回复会被保存在客户端状态的输出缓冲区里面, 每个客户端都有两个输出缓冲区:

    • 固定大小的缓冲区用于保存那些长度比较小的回复, 比如 OK 、简短的字符串值、整数值、错误回复,等等。
    • 可变大小的缓冲区用于保存那些长度比较大的回复, 比如一个非常长的字符串值, 一个由很多项组成的列表, 一个包含了很多元素的集合, 等等。

    3.3.6、其它

    客户端状态的 authenticated 属性用于记录客户端是否通过了身份验证,还有几个和时间有关的属性,叙述是一件挺无聊的事情,不再写。

     

    3.4、命令的执行过程

    3.4.1发送命令请求

    当用户在客户端中键入一个命令请求时, 客户端会将这个命令请求转换成协议格式, 然后通过连接到服务器的套接字, 将协议格式的命令请求发送给服务器。

    3.4.2读取命令请求

    当客户端与服务器之间的连接套接字因为客户端的写入而变得可读时, 服务器将调用命令请求处理器来执行以下操作:

    1. 读取套接字中协议格式的命令请求, 并将其保存到客户端状态的输入缓冲区里面。
    2. 对输入缓冲区中的命令请求进行分析, 提取出命令请求中包含的命令参数, 以及命令参数的个数, 然后分别将参数和参数个数保存到客户端状态的 argv 属性和 argc 属性里面。
    3. 调用命令执行器, 执行客户端指定的命令。

    3.4.3命令执行器:查找命令实现

    命令执行器要做的第一件事就是根据客户端状态的 argv[0] 参数, 在命令表(command table)中查找参数所指定的命令, 并将找到的命令保存到客户端状态的 cmd 属性里面。

    命令表是一个字典, 字典的键是一个个命令名字,比如 "set" 、 "get" 、 "del" ,等等; 而字典的值是一个个 redisCommand 结构, 每个 redisCommand 结构记录了一个 Redis 命令的实现信息。

    命令名字的大小写不影响命令表的查找结果

    因为命令表使用的是大小写无关的查找算法, 无论输入的命令名字是大写、小写或者混合大小写, 只要命令的名字是正确的, 就能找到相应的 redisCommand 结构。

    比如说, 无论用户输入的命令名字是 "SET" 、 "set" 、 "SeT" 又或者 "sEt" , 命令表返回的都是同一个 redisCommand 结构。

    redis> SET msg "hello world"
    OK
    
    redis> set msg "hello world"
    OK
    
    redis> SeT msg "hello world"
    OK
    
    redis> sEt msg "hello world"
    OK

    3.4.4命令执行器:执行预备操作

    到目前为止, 服务器已经将执行命令所需的命令实现函数(保存在客户端状态的 cmd 属性)、参数(保存在客户端状态的 argv 属性)、参数个数(保存在客户端状态的 argc 属性)都收集齐了, 但是在真正执行命令之前, 程序还需要进行一些预备操作, 从而确保命令可以正确、顺利地被执行, 这些操作包括:

    • 检查客户端状态的 cmd 指针是否指向 NULL , 如果是的话, 那么说明用户输入的命令名字找不到相应的命令实现, 服务器不再执行后续步骤, 并向客户端返回一个错误。
    • 根据客户端 cmd 属性指向的 redisCommand 结构的 arity 属性, 检查命令请求所给定的参数个数是否正确, 当参数个数不正确时, 不再执行后续步骤, 直接向客户端返回一个错误。 比如说, 如果 redisCommand 结构的 arity 属性的值为 -3 , 那么用户输入的命令参数个数必须大于等于 3 个才行。
    • 检查客户端是否已经通过了身份验证, 未通过身份验证的客户端只能执行 AUTH 命令, 如果未通过身份验证的客户端试图执行除 AUTH 命令之外的其他命令, 那么服务器将向客户端返回一个错误。
    • 如果服务器打开了 maxmemory 功能, 那么在执行命令之前, 先检查服务器的内存占用情况, 并在有需要时进行内存回收, 从而使得接下来的命令可以顺利执行。 如果内存回收失败, 那么不再执行后续步骤, 向客户端返回一个错误。
    • 如果服务器上一次执行 BGSAVE 命令时出错, 并且服务器打开了 stop-writes-on-bgsave-error 功能, 而且服务器即将要执行的命令是一个写命令, 那么服务器将拒绝执行这个命令, 并向客户端返回一个错误。
    • 如果客户端当前正在用 SUBSCRIBE 命令订阅频道, 或者正在用 PSUBSCRIBE 命令订阅模式, 那么服务器只会执行客户端发来的 SUBSCRIBE 、 PSUBSCRIBE 、 UNSUBSCRIBE 、 PUNSUBSCRIBE 四个命令, 其他别的命令都会被服务器拒绝。
    • 如果服务器正在进行数据载入, 那么客户端发送的命令必须带有 l 标识(比如 INFO 、 SHUTDOWN 、 PUBLISH ,等等)才会被服务器执行, 其他别的命令都会被服务器拒绝。
    • 如果服务器因为执行 Lua 脚本而超时并进入阻塞状态, 那么服务器只会执行客户端发来的 SHUTDOWN nosave 命令和 SCRIPT KILL 命令, 其他别的命令都会被服务器拒绝。
    • 如果客户端正在执行事务, 那么服务器只会执行客户端发来的 EXEC 、 DISCARD 、 MULTI 、 WATCH 四个命令, 其他命令都会被放进事务队列中。
    • 如果服务器打开了监视器功能, 那么服务器会将要执行的命令和参数等信息发送给监视器。

    当完成了以上预备操作之后, 服务器就可以开始真正执行命令了。

    3.4.5命令执行器:调用命令的实现函数

    在前面的操作中, 服务器已经将要执行命令的实现保存到了客户端状态的 cmd 属性里面, 并将命令的参数和参数个数分别保存到了客户端状态的 argv 属性和 argc 属性里面, 当服务器决定要执行命令时, 它只要执行以下语句就可以了:

    // client 是指向客户端状态的指针
    
    client->cmd->proc(client);

    因为执行命令所需的实际参数都已经保存到客户端状态的 argv 属性里面了, 所以命令的实现函数只需要一个指向客户端状态的指针作为参数即可。

    3.4.6命令执行器:执行后续工作

    在执行完实现函数之后, 服务器还需要执行一些后续工作:

    • 如果服务器开启了慢查询日志功能, 那么慢查询日志模块会检查是否需要为刚刚执行完的命令请求添加一条新的慢查询日志。
    • 根据刚刚执行命令所耗费的时长, 更新被执行命令的 redisCommand 结构的 milliseconds 属性, 并将命令的 redisCommand 结构的 calls 计数器的值增一。
    • 如果服务器开启了 AOF 持久化功能, 那么 AOF 持久化模块会将刚刚执行的命令请求写入到 AOF 缓冲区里面。
    • 如果有其他从服务器正在复制当前这个服务器, 那么服务器会将刚刚执行的命令传播给所有从服务器。

    当以上操作都执行完了之后, 服务器对于当前命令的执行到此就告一段落了, 之后服务器就可以继续从文件事件处理器中取出并处理下一个命令请求了。

    3.4.7将命令回复发送给客户端

    前面说过, 命令实现函数会将命令回复保存到客户端的输出缓冲区里面, 并为客户端的套接字关联命令回复处理器, 当客户端套接字变为可写状态时, 服务器就会执行命令回复处理器, 将保存在客户端输出缓冲区中的命令回复发送给客户端。

    当命令回复发送完毕之后, 回复处理器会清空客户端状态的输出缓冲区, 为处理下一个命令请求做好准备。

    3.4.8客户端接收并打印命令回复

    当客户端接收到协议格式的命令回复之后, 它会将这些回复转换成人类可读的格式, 并打印给用户观看(假设使用的是 Redis 自带的 客户端)

     

    3.5、事务

    Redis 事务可以一次执行多个命令, 并且带有以下三个重要的保证:

    • 批量操作在发送 EXEC 命令前被放入队列缓存。
    • 收到 EXEC 命令后进入事务执行,事务中任意命令执行失败,其余的命令依然被执行。
    • 在事务执行过程,其他客户端提交的命令请求不会插入到事务执行命令序列中。

    一个事务从开始到执行会经历以下三个阶段:

    • 开始事务。
    • 命令入队。
    • 执行事务。

    以下是一个事务的例子, 它先以 MULTI 开始一个事务, 然后将多个命令入队到事务中, 最后由 EXEC 命令触发事务, 一并执行事务中的所有命令:

    redis 127.0.0.1:6379> MULTI
    OK
    
    redis 127.0.0.1:6379> SET book-name "Mastering C++ in 21 days"
    QUEUED
    
    redis 127.0.0.1:6379> GET book-name
    QUEUED
    
    redis 127.0.0.1:6379> SADD tag "C++" "Programming" "Mastering Series"
    QUEUED
    
    redis 127.0.0.1:6379> SMEMBERS tag
    QUEUED
    
    redis 127.0.0.1:6379> EXEC
    1) OK
    2) "Mastering C++ in 21 days"
    3) (integer) 3
    4) 1) "Mastering Series"
       2) "C++"
       3) "Programming"

    详细介绍:

    3.5.1事务开始

    MULTI 命令的执行标志着事务的开始:

    redis> MULTI
    OK
    

    MULTI 命令可以将执行该命令的客户端从非事务状态切换至事务状态, 这一切换是通过在客户端状态的 flags 属性中打开 REDIS_MULTI 标识来完成的, MULTI 命令的实现可以用以下伪代码来表示:

    def MULTI():
    
        # 打开事务标识
        client.flags |= REDIS_MULTI
    
        # 返回 OK 回复
        replyOK()

    3.5.2命令入队

    当一个客户端处于非事务状态时, 这个客户端发送的命令会立即被服务器执行:

    redis> SET "name" "Practical Common Lisp"
    OK
    
    redis> GET "name"
    "Practical Common Lisp"
    
    redis> SET "author" "Peter Seibel"
    OK
    
    redis> GET "author"
    "Peter Seibel"

    与此不同的是, 当一个客户端切换到事务状态之后, 服务器会根据这个客户端发来的不同命令执行不同的操作:

    • 如果客户端发送的命令为 EXEC 、 DISCARD 、 WATCH 、 MULTI 四个命令的其中一个, 那么服务器立即执行这个命令。
    • 与此相反, 如果客户端发送的命令是 EXEC 、 DISCARD 、 WATCH 、 MULTI 四个命令以外的其他命令, 那么服务器并不立即执行这个命令, 而是将这个命令放入一个事务队列里面, 然后向客户端返回 QUEUED 回复。

    3.5.3事务队列

    每个 Redis 客户端都有自己的事务状态, 这个事务状态保存在客户端状态的 mstate 属性里面:

    typedef struct redisClient {
    
        // ...
    
        // 事务状态
        multiState mstate;      /* MULTI/EXEC state */
    
        // ...
    
    } redisClient;

    事务状态包含一个事务队列, 以及一个已入队命令的计数器 (也可以说是事务队列的长度):

    typedef struct multiState {
    
        // 事务队列,FIFO 顺序
        multiCmd *commands;
    
        // 已入队命令计数
        int count;
    
    } multiState;

    事务队列是一个 multiCmd 类型的数组, 数组中的每个 multiCmd 结构都保存了一个已入队命令的相关信息, 包括指向命令实现函数的指针, 命令的参数, 以及参数的数量:

    typedef struct multiCmd {
    
        // 参数
        robj **argv;
    
        // 参数数量
        int argc;
    
        // 命令指针
        struct redisCommand *cmd;
    
    } multiCmd;

    事务队列以先进先出(FIFO)的方式保存入队的命令: 较先入队的命令会被放到数组的前面, 而较后入队的命令则会被放到数组的后面。

    举个例子, 如果客户端执行以下命令:

    redis> MULTI
    OK
    
    redis> SET "name" "Practical Common Lisp"
    QUEUED
    
    redis> GET "name"
    QUEUED
    
    redis> SET "author" "Peter Seibel"
    QUEUED
    
    redis> GET "author"
    QUEUED
    

    那么服务器将为客户端创建事务状态:

    • 最先入队的 SET 命令被放在了事务队列的索引 0 位置上。
    • 第二入队的 GET 命令被放在了事务队列的索引 1 位置上。
    • 第三入队的另一个 SET 命令被放在了事务队列的索引 2 位置上。
    • 最后入队的另一个 GET 命令被放在了事务队列的索引 3 位置上。

    3.5.4执行事务

    当一个处于事务状态的客户端向服务器发送 EXEC 命令时, 这个 EXEC 命令将立即被服务器执行: 服务器会遍历这个客户端的事务队列, 执行队列中保存的所有命令, 最后将执行命令所得的结果全部返回给客户端。

    EXEC 命令的实现原理可以用以下伪代码来描述:

    def EXEC():
    
        # 创建空白的回复队列
        reply_queue = []
    
        # 遍历事务队列中的每个项
        # 读取命令的参数,参数的个数,以及要执行的命令
        for argv, argc, cmd in client.mstate.commands:
    
            # 执行命令,并取得命令的返回值
            reply = execute_command(cmd, argv, argc)
    
            # 将返回值追加到回复队列末尾
            reply_queue.append(reply)
    
        # 移除 REDIS_MULTI 标识,让客户端回到非事务状态
        client.flags &= ~REDIS_MULTI
    
        # 清空客户端的事务状态,包括:
        # 1)清零入队命令计数器
        # 2)释放事务队列
        client.mstate.count = 0
        release_transaction_queue(client.mstate.commands)
    
        # 将事务的执行结果返回给客户端
        send_reply_to_client(client, reply_queue)

    3.5.5WATCH命令的实现

    WATCH命令是一个乐观锁,它可以在EXEC命令执行之前,监视任意数量的数据库键,并在EXEC执行后,检查被监视的键是否至少有一个被修改,如果是,服务器拒绝执行事务,并向客户端返回代表事务执行失败的回复。

    /* Redis database representation. There are multiple databases identified
     * by integers from 0 (the default database) up to the max configured
     * database. The database number is the 'id' field in the structure. */
    typedef struct redisDb {
        dict *dict;                 /* The keyspace for this DB 数据库键空间,保存数据库中所有的键值对*/
        dict *expires;              /* Timeout of keys with a timeout set 保存过期时间*/
        dict *blocking_keys;        /* Keys with clients waiting for data (BLPOP) */
        dict *ready_keys;           /* Blocked keys that received a PUSH 已经准备好数据的阻塞状态的key*/
        dict *watched_keys;         /* WATCHED keys for MULTI/EXEC CAS 事物模块,用于保存被WATCH命令所监控的键*/
         // 当内存不足时,Redis会根据LRU算法回收一部分键所占的空间,而该eviction_pool是一个长为16数组,保存可能被回收的键
        // eviction_pool中所有键按照idle空转时间,从小到大排序,每次回收空转时间最长的键
        struct evictionPoolEntry *eviction_pool;    /* Eviction pool of keys */
           // 数据库ID
        int id;                     /* Database ID */
         // 键的平均过期时间
        long long avg_ttl;          /* Average TTL, just for stats */
    } redisDb;

    在每个代表数据库的 server.h/redisDb 结构类型中, 都保存了一个 watched_keys 字典, 字典的键是这个数据库被监视的键, 而字典的值则是一个链表, 链表中保存了所有监视这个键的客户端。比如说,以下字典就展示了一个 watched_keys 字典的例子:

    每个key后挂着监视自己的客户端。

    3.5.6监控的触发

    在任何对数据库键空间(key space)进行修改的命令成功执行之后 (比如 FLUSHDB 、 SET 、 DEL 、 LPUSH 、 SADD 、 ZREM ,诸如此类), multi.c/touchWatchedKey 函数都会被调用 (修改命令会调用signalModifiedKey()函数来处理数据库中的键被修改的情况,该函数直接调用touchWatchedKey()函数)—— 它检查数据库的 watched_keys 字典, 看是否有客户端在监视已经被命令修改的键, 如果有的话, 程序将所有监视这个/这些被修改键的客户端的 REDIS_DIRTY_CAS 选项打开:
     

    /* "Touch" a key, so that if this key is being WATCHed by some client the
     * next EXEC will fail. */
    // Touch 一个 key,如果该key正在被监视,那么客户端会执行EXEC失败 
    void touchWatchedKey(redisDb *db, robj *key) {
        list *clients;
        listIter li;
        listNode *ln;
        
        // 字典为空,没有任何键被监视
        if (dictSize(db->watched_keys) == 0) return;
        // 获取所有监视这个键的客户端 	
        clients = dictFetchValue(db->watched_keys, key);
        // 没找到返回
        if (!clients) return;
     
        /* Mark all the clients watching this key as CLIENT_DIRTY_CAS */
        /* Check if we are already watching for this key */
        // 遍历所有客户端,打开他们的 REDIS_DIRTY_CAS 标识
        listRewind(clients,&li);
        while((ln = listNext(&li))) {
            client *c = listNodeValue(ln);
            
             // 设置CLIENT_DIRTY_CAS标识
            c->flags |= CLIENT_DIRTY_CAS;
        }
    }

    3.5.7事务的ACID性质

     在传统的关系式数据库中,常常用 ACID 性质来检验事务功能的安全性。

    redis事物总是具有前三个性质。

    a)原子性atomicity:redis事务保证事务中的命令要么全部执行要不全部不执行。

    但是redis不同于传统关系型数据库,不支持回滚,即使出现了错误,事务也会继续执行下去。

    因为redis作者认为,这种复杂的机制和redis追求的简单高效不符。并且,redis事务错误通常是编程错误,只会出现在开发环境中,而不会出现在实际生产环境中,所以没必要支持回滚。

    b)一致性consistency:redis事务可以保证命令失败的情况下得以回滚,数据能恢复到没有执行之前的样子,是保证一致性的,除非redis进程意外终结。

    Redis 的一致性问题可以分为三部分来讨论:入队错误、执行错误、Redis 进程被终结。

    入队错误

    在命令入队的过程中,如果客户端向服务器发送了错误的命令,比如命令的参数数量不对,等等, 那么服务器将向客户端返回一个出错信息, 并且将客户端的事务状态设为 REDIS_DIRTY_EXEC 。
    因此,带有不正确入队命令的事务不会被执行,也不会影响数据库的一致性。

    执行错误

    如果命令在事务执行的过程中发生错误,比如说,对一个不同类型的 key 执行了错误的操作, 那么 Redis 只会将错误包含在事务的结果中, 这不会引起事务中断或整个失败,不会影响已执行事务命令的结果,也不会影响后面要执行的事务命令, 所以它对事务的一致性也没有影响。

    Redis 进程被终结

    如果 Redis 服务器进程在执行事务的过程中被其他进程终结,或者被管理员强制杀死,那么根据 Redis 所使用的持久化模式,可能有以下情况出现:

    内存模式:如果 Redis 没有采取任何持久化机制,那么重启之后的数据库总是空白的,所以数据总是一致的。

    RDB 模式:在执行事务时,Redis 不会中断事务去执行保存 RDB 的工作,只有在事务执行之后,保存 RDB 的工作才有可能开始。所以当 RDB 模式下的 Redis 服务器进程在事务中途被杀死时,事务内执行的命令,不管成功了多少,都不会被保存到 RDB 文件里。恢复数据库需要使用现有的 RDB 文件,而这个 RDB 文件的数据保存的是最近一次的数据库快照(snapshot),所以它的数据可能不是最新的,但只要 RDB 文件本身没有因为其他问题而出错,那么还原后的数据库就是一致的。

    AOF 模式:因为保存 AOF 文件的工作在后台线程进行,所以即使是在事务执行的中途,保存 AOF 文件的工作也可以继续进行,因此,根据事务语句是否被写入并保存到 AOF 文件,有以下两种情况发生:

    1)如果事务语句未写入到 AOF 文件,或 AOF 未被 SYNC 调用保存到磁盘,那么当进程被杀死之后,Redis 可以根据最近一次成功保存到磁盘的 AOF 文件来还原数据库,只要 AOF 文件本身没有因为其他问题而出错,那么还原后的数据库总是一致的,但其中的数据不一定是最新的。

    2)如果事务的部分语句被写入到 AOF 文件,并且 AOF 文件被成功保存,那么不完整的事务执行信息就会遗留在 AOF 文件里,当重启 Redis 时,程序会检测到 AOF 文件并不完整,Redis 会退出,并报告错误。需要使用 redis-check-aof 工具将部分成功的事务命令移除之后,才能再次启动服务器。还原之后的数据总是一致的,而且数据也是最新的(直到事务执行之前为止)。
     

    c)隔离性Isolation:redis事务是严格遵守隔离性的,原因是redis是单进程单线程模式,可以保证命令执行过程中不会被其他客户端命令打断。

    因为redis使用单线程执行事务,并且保证不会中断,所以肯定有隔离性。

    d)持久性Durability:持久性是指:当一个事务执行完毕,结果已经保存在永久介质里,比如硬盘,所以即使服务器后来停机了,结果也不会丢失

    redis事务是不保证持久性的,这是因为redis持久化策略中不管是RDB还是AOF都是异步执行的,不保证持久性是出于对性能的考虑。


    3.5.8重点提炼

    • 事务提供了一种将多个命令打包, 然后一次性、有序地执行的机制。
    • 多个命令会被入队到事务队列中, 然后按先进先出(FIFO)的顺序执行。
    • 事务在执行过程中不会被中断, 当事务队列中的所有命令都被执行完毕之后, 事务才会结束。
    • 带有 WATCH 命令的事务会将客户端和被监视的键在数据库的 watched_keys 字典中进行关联, 当键被修改时, 程序会将所有监视被修改键的客户端的 REDIS_DIRTY_CAS 标志打开。
    • 只有在客户端的 REDIS_DIRTY_CAS 标志未被打开时, 服务器才会执行客户端提交的事务, 否则的话, 服务器将拒绝执行客户端提交的事务。
    • Redis 的事务总是保证 ACID 中的原子性、一致性和隔离性, 当服务器运行在 AOF 持久化模式下, 并且 appendfsync 选项的值为 always 时, 事务也具有耐久性。

     

    以上就是 Redis 客户端和服务器执行命令请求的整个过程了。

     

    3.6、发布和订阅

    3.6.1频道的订阅和退订

    当一个客户端执行 SUBSCRIBE 命令, 订阅某个或某些频道的时候, 这个客户端与被订阅频道之间就建立起了一种订阅关系。

    Redis 将所有频道的订阅关系都保存在服务器状态的 pubsub_channels 字典里面, 这个字典的键是某个被订阅的频道, 而键的值则是一个链表, 链表里面记录了所有订阅这个频道的客户端:

    struct redisServer {
    
        // ...
    
        // 保存所有频道的订阅关系
        dict *pubsub_channels;
    
        // ...
    
    };

    每当客户端执行 SUBSCRIBE 命令, 订阅某个或某些频道的时候, 服务器都会将客户端与被订阅的频道在 pubsub_channels 字典中进行关联。

    根据频道是否已经有其他订阅者, 关联操作分为两种情况执行:

    • 如果频道已经有其他订阅者, 那么它在 pubsub_channels 字典中必然有相应的订阅者链表, 程序唯一要做的就是将客户端添加到订阅者链表的末尾。
    • 如果频道还未有任何订阅者, 那么它必然不存在于 pubsub_channels 字典, 程序首先要在 pubsub_channels 字典中为频道创建一个键, 并将这个键的值设置为空链表, 然后再将客户端添加到链表, 成为链表的第一个元素。

    SUBSCRIBE 命令的实现可以用以下伪代码来描述:

    def subscribe(*all_input_channels):
    
        # 遍历输入的所有频道
        for channel in all_input_channels:
    
            # 如果 channel 不存在于 pubsub_channels 字典(没有任何订阅者)
            # 那么在字典中添加 channel 键,并设置它的值为空链表
            if channel not in server.pubsub_channels:
                server.pubsub_channels[channel] = []
    
            # 将订阅者添加到频道所对应的链表的末尾
            server.pubsub_channels[channel].append(client)

     

    UNSUBSCRIBE 命令的行为和 SUBSCRIBE 命令的行为正好相反 —— 当一个客户端退订某个或某些频道的时候, 服务器将从 pubsub_channels 中解除客户端与被退订频道之间的关联:

    • 程序会根据被退订频道的名字, 在 pubsub_channels 字典中找到频道对应的订阅者链表, 然后从订阅者链表中删除退订客户端的信息。
    • 如果删除退订客户端之后, 频道的订阅者链表变成了空链表, 那么说明这个频道已经没有任何订阅者了, 程序将从 pubsub_channels 字典中删除频道对应的键。

    UNSUBSCRIBE 命令的实现可以用以下伪代码来描述:

    def unsubscribe(*all_input_channels):
    
        # 遍历要退订的所有频道
        for channel in all_input_channels:
    
            # 在订阅者链表中删除退订的客户端
            server.pubsub_channels[channel].remove(client)
    
            # 如果频道已经没有任何订阅者了(订阅者链表为空)
            # 那么将频道从字典中删除
            if len(server.pubsub_channels[channel]) == 0:
                server.pubsub_channels.remove(channel)

    3.6.2模式的订阅和退订

    前面说过,服务器将所有频道的订阅关系保存起来,与此类似,服务器也将所有模式的订阅关系存在了pubsub_Patterns属性里。

    struct redisServer {
    
        // ...
    
        // 保存所有频道的订阅关系
        list *pubsub_patterns;
    
        // ...
    
    };

    pubsub_Patterns属性是一个链表,每个结点是被订阅的模式,节点内记录了模式,节点内的client属性记录了订阅模式的客户端。

    typedef struct pubsubPattern{
        //订阅模式的客户端
        redisClient *client;
        //被订阅的模式
        robj *pattern;
    }pubsubPattern;

    每当客户端执行PSUBSCRIBE这个命令来订阅某个或某些模式时,服务器会对每个被订阅的模式执行下面的操作:

    1)新建一个pubsubPattern结构,设置好两个属性

    2)将新节点加到pubsub_patterns尾部

    伪代码实现:

    def osubscribe(*all_input_patterns):
        #遍历所有输入的模式
        #记录被订阅的模式和对应的客户端
        pubsubPattern=create()
        pubsubPattern.client=client
        pubsubPattern.pattern=pattern
    
        #插入链表末尾
        server.pub_patterns.append(pubsubPattern)

    模式退订命令PUNSUBSCRIBE是PSUBSCRIBE的反操作

    服务器将找到并删除那些被退订的模式

    伪代码如下:(我想吐槽一下这样时间复杂度。。。没有更好的办法吗?)

    def osubscribe(*all_input_patterns):
        #遍历所有退订的模式
        for pattern in all_input_patterns:
            #遍历每一个节点
            for pubsubPattern in server.pubsub_patterns:
                #如果客户端和模式都相同
                if client==pubsubPattern.client:
                    if pattern==pubsubPattern.pattern:
                        #删除
                        server.pub_patterns.remove(pubsubPattern)

    3.6.3、发送消息

    当一个客户端执行PUBLISH<channel> <message>命令将消息发送给频道时,服务器需要:

    1)把消息发送给所有本频道的订阅者

    具体做法就是去pubsub_channels字典找到本频道的链表,也就是订阅名单,然后发消息

    2)将消息发给,包含本频道的所有模式中的所有订阅者

    具体做法就是去pubsub_patterns查找包含本频道的模式,并且把消息发送给订阅它们的客户端。

    3.6.4、查看订阅信息

    redis2.8新增三个命令,用来查看频道和模式的相关信息。

    PUBLISH CHANNELS[pattern]用于返回服务器当前被订阅的频道,pattern可写可不写,不写就查看所有,否则查看与pattern匹配的对应频道

    这个子命令是通过遍历pubsub_channels字典实现的。

    PUBLISH NUMSUB[CHANNEL-1 CHANNEL-2.....]返回这些频道的订阅者数量

    这个子命令是通过遍历pubsub_channels字典,查看对应链表长度实现的。

    PUBLISH NUMPAT返回被订阅模式数量

    这个子命令是通过返回pubsub_patterns的长度实现的。

    总而言之,PUBSUB 命令的三个子命令都是通过读取 pubsub_channels 字典和 pubsub_patterns 链表中的信息来实现的。

     

    4、多机实现

    4.1、旧版复制

    Redis 的复制功能分为同步(sync)和命令传播(command propagate)两个操作:

    • 同步操作用于将从服务器的数据库状态更新至主服务器当前所处的数据库状态。
    • 命令传播操作用于在主服务器的数据库状态被修改, 导致主从服务器的数据库状态出现不一致时, 让主从服务器的数据库重新回到一致状态。

    同步

    当客户端向从服务器发送 SLAVEOF 命令, 要求从服务器复制主服务器时, 从服务器首先需要执行同步操作, 也即是, 将从服务器的数据库状态更新至主服务器当前所处的数据库状态。

    从服务器对主服务器的同步操作需要通过向主服务器发送 SYNC 命令来完成, 以下是 SYNC 命令的执行步骤:

    1. 从服务器向主服务器发送 SYNC 命令。
    2. 收到 SYNC 命令的主服务器执行 BGSAVE 命令, 在后台生成一个 RDB 文件, 并使用一个缓冲区记录从现在开始执行的所有写命令。
    3. 当主服务器的 BGSAVE 命令执行完毕时, 主服务器会将 BGSAVE 命令生成的 RDB 文件发送给从服务器, 从服务器接收并载入这个 RDB 文件, 将自己的数据库状态更新至主服务器执行 BGSAVE 命令时的数据库状态。
    4. 主服务器将记录在缓冲区里面的所有写命令发送给从服务器, 从服务器执行这些写命令, 将自己的数据库状态更新至主服务器数据库当前所处的状态。

    命令传播

    在同步操作执行完毕之后, 主从服务器两者的数据库将达到一致状态, 但这种一致并不是一成不变的 —— 每当主服务器执行客户端发送的写命令时, 主服务器的数据库就有可能会被修改, 并导致主从服务器状态不再一致。

    举个例子, 假设一个主服务器和一个从服务器刚刚完成同步操作, 它们的数据库都保存了相同的五个键 k1 至 k5

    如果这时, 客户端向主服务器发送命令 DEL k3 , 那么主服务器在执行完这个 DEL 命令之后, 主从服务器的数据库将出现不一致: 主服务器的数据库已经不再包含键 k3 , 但这个键却仍然包含在从服务器的数据库里面

    为了让主从服务器再次回到一致状态, 主服务器需要对从服务器执行命令传播操作: 主服务器会将自己执行的写命令 —— 也即是造成主从服务器不一致的那条写命令 —— 发送给从服务器执行, 当从服务器执行了相同的写命令之后, 主从服务器将再次回到一致状态。

    缺陷

     其中可以明显看出重新连接主服务器之后,SYNC命令创建包含k1-k10089的RDB文件。而事实上只需要再同步断线后的k10087-k10089即可。SYNC的“全同步”对于从服务来说是不必要的。

               SYNC命令非常消耗资源,原因有三点:

        1)主服务器执行BGSAVE命令生成RDB文件,这个生成过程会大量消耗主服务器资源(CPU、内存和磁盘I/O资源)

        2)主服务器需要将自己生成的RBD文件发送给从从服务器,这个发送操作会消耗主从服务器大量的网络资源(带宽与流量)

        3)接收到RDB文件你的从服务器需要载入RDB文件,载入期间从服务器会因为阻塞而导致没办法处理命令请求。

    4.2新版复制

    sync虽然解决了数据同步问题,但是在数据量比较大情况下,从库断线从来依然采用全量复制机制,无论是从数据恢复、宽带占用来说,sync所带来的问题还是很多的。于是redis从2.8开始,引入新的命令psync。

    psync有两种模式:完整重同步和部分重同步。

    部分重同步主要依赖三个方面来实现,依次介绍。

    offset(复制偏移量):

    主库和从库分别各自维护一个复制偏移量(可以使用info replication查看),用于标识自己复制的情况:

    在主库中代表主节点向从节点传递的字节数,在从库中代表从库同步的字节数。

    每当主库向从节点发送N个字节数据时,主节点的offset增加N

    从库每收到主节点传来的N个字节数据时,从库的offset增加N。

    因此offset总是不断增大,这也是判断主从数据是否同步的标志,若主从的offset相同则表示数据同步量,不通则表示数据不同步。

    replication backlog buffer(复制积压缓冲区):

      复制积压缓冲区是一个固定长度的FIFO队列,大小由配置参数repl-backlog-size指定,默认大小1MB。

    需要注意的是该缓冲区由master维护并且有且只有一个,所有slave共享此缓冲区,其作用在于备份最近主库发送给从库的数据。

      在主从命令传播阶段,主节点除了将写命令发送给从节点外,还会发送一份到复制积压缓冲区,作为写命令的备份。

     

    除了存储最近的写命令,复制积压缓冲区中还存储了每个字节相应的复制偏移量,由于复制积压缓冲区固定大小先进先出的队列,所以它总是保存的是最近redis执行的命令。

    所以,重连服务器后,从服务器会发送自己的复制偏移量offset给主服务器,

    如果offset偏移量之后的数据仍然存在于复制挤压缓冲区,就执行部分重同步操作。

    相反,执行完整重同步操作。

    run_id(服务器运行的唯一ID) 

      每个redis实例在启动时候,都会随机生成一个长度为40的唯一字符串来标识当前运行的redis节点,查看此id可通过命令info server查看。

      当主从复制在初次复制时,主节点将自己的runid发送给从节点,从节点将这个runid保存起来,当断线重连时,从节点会将这个runid发送给主节点。主节点根据runid判断能否进行部分复制:

    • 如果从节点保存的runid与主节点现在的runid相同,说明主从节点之前同步过,主节点会更具offset偏移量之后的数据判断是否执行部分复制,如果offset偏移量之后的数据仍然都在复制积压缓冲区里,则执行部分复制,否则执行全量复制;
    • 如果从节点保存的runid与主节点现在的runid不同,说明从节点在断线前同步的redis节点并不是当前的主节点,只能进行全量复制;

     

    psync流程:

    复制

    客户端向服务器端发送:SLAVEOF

    1、设置主服务器的地址和端口

    存到masterhost和mastterport两个属性里之后,向客户端发送ok,然后开始复制工作。

    2、建立套接字链接

    从服务器根据命令设置的地址和端口,创建链接,并且为这个套接字创建一个专门处理复制工作的文件事件处理器。

    主服务器也会为套接字创建相应的客户端状态,并且把从服务器当作一个客户端来对待。

    3、发送ping命令(检查)

    检查套接字状态是否正常

    检查主服务器是否能正确处理请求。(如果不能,就重连)

    4、身份认证

     

    5、发送端口信息

    从服务器向主服务器发送信息,主服务器记录。

    6、同步

    从服务器向主服务器发送psync命令。(主服务器也成为从服务器的客户端,因为主服务器会发送写命令给从服务器)

    7、命令传播

    完成同步后,进入传播阶段,主服务器一直发送写命令,从服务器一直接受,保证和主服务器一致。

    心跳检测

    默认一秒一次,从服务器向主服务器发送命令:REPLCONF ACK <offset>

    三个作用:

    检测网络连接状态:如果主服务器一秒没收到命令,就说明出问题了

    辅助实现min-slaves配置:min-slaves-to-write 3   min-slaves-max-log 10:当从服务器小于3个或延迟都大于10,主服务器拒绝写命令。

    检测命令丢失:如果命令丢失,主服务器会发现偏移量不一样,然后它就会根据偏移量,去积压缓冲区找到缺少的数据并发给从服务器。

    4.3、哨兵

    4.3.1什么是哨兵机制

    Redis的哨兵(sentinel) 系统用于管理/多个 Redis 服务器,该系统执行以下三个任务:

    ·        监控: 哨兵(sentinel) 会不断地检查你的Master和Slave是否运作正常。

    ·        提醒:当被监控的某个 Redis出现问题时, 哨兵(sentinel) 可以通过 API 向管理员或者其他应用程序发送通知。

    ·        自动故障迁移:当一个Master不能正常工作时,哨兵(sentinel) 会开始一次自动故障迁移操作,它会将失效Master的其中一个Slave升级为新的Master, 并让失效Master的其他Slave改为复制新的Master; 当客户端试图连接失效的Master时,集群也会向客户端返回新Master的地址,使得集群可以使用Master代替失效Master。

    例如下图所示:

    在Server1 掉线后:

    升级Server2 为新的主服务器:

    4.3.2、哨兵模式修改配置

    实现步骤:

    1.拷贝到etc目录

    cp sentinel.conf  /usr/local/redis/etc

    2.修改sentinel.conf配置文件

    sentinel monitor mymast  192.168.110.133 6379 1  #主节点 名称 IP 端口号 选举次数

    sentinel auth-pass mymaster 123456 

    3. 修改心跳检测 5000毫秒

    sentinel down-after-milliseconds mymaster 5000

    4.sentinel parallel-syncs mymaster 2 --- 做多多少合格节点

    5. 启动哨兵模式

    ./redis-server /usr/local/redis/etc/sentinel.conf --sentinel &


    1)Sentinel(哨兵) 进程是用于监控 Redis 集群中 Master 主服务器工作的状态

    2)在 Master 主服务器发生故障的时候,可以实现 Master 和 Slave 服务器的切换,保证系统的高可用(High Availability)

    工作方式

    1)每个 Sentinel(哨兵)进程以每秒钟一次的频率向整个集群中的 Master 主服务器,Slave 从服务器以及其他 Sentinel(哨兵)进程发送一个 PING 命令。

    2. 如果一个实例(instance)距离最后一次有效回复 PING 命令的时间超过 down-after-milliseconds 选项所指定的值, 则这个实例会被 Sentinel(哨兵)进程标记为主观下线。

    3. 如果一个 Master 主服务器被标记为主观下线,则正在监视这个 Master 主服务器的所有 Sentinel(哨兵)进程要以每秒一次的频率确认 Master 主服务器的确进入了主观下线状态。

    4. 当有足够数量的 Sentinel(哨兵)进程(大于等于配置文件指定的值)在指定的时间范围内确认 Master 主服务器进入了主观下线状态, 则Master 主服务器会被标记为客观下线(ODOWN)。

    5. 在一般情况下, 每个 Sentinel(哨兵)进程会以每 10 秒一次的频率向集群中的所有Master 主服务器、Slave 从服务器发送 INFO 命令。

    6. 当 Master 主服务器被 Sentinel(哨兵)进程标记为客观下线时,Sentinel(哨兵)进程向下线的 Master 主服务器的所有 Slave 从服务器发送 INFO 命令的频率会从 10 秒一次改为每秒一次。

    7. 若没有足够数量的 Sentinel(哨兵)进程同意 Master 主服务器下线, Master 主服务器的客观下线状态就会被移除。若 Master 主服务器重新向 Sentinel(哨兵)进程发送 PING 命令返回有效回复,Master 主服务器的主观下线状态就会被移除。

    哨兵(sentinel) 的一些设计思路和zookeeper非常类似


    我们从启动并初始化说起

    4.3.3启动并初始化 Sentinel

    启动一个 Sentinel 可以使用命令:

    $ redis-sentinel /path/to/your/sentinel.conf
    

    或者命令:

    $ redis-server /path/to/your/sentinel.conf --sentinel
    
    

    当一个 Sentinel 启动时, 它需要执行以下步骤:

    初始化服务器。

    首先, 因为 Sentinel 本质上只是一个运行在特殊模式下的 Redis 服务器, 所以启动 Sentinel 的第一步, 就是初始化一个普通的 Redis 服务器.

    不过, 因为 Sentinel 执行的工作和普通 Redis 服务器执行的工作不同, 所以 Sentinel 的初始化过程和普通 Redis 服务器的初始化过程并不完全相同。

    比如说, 普通服务器在初始化时会通过载入 RDB 文件或者 AOF 文件来还原数据库状态, 但是因为 Sentinel 并不使用数据库, 所以初始化 Sentinel 时就不会载入 RDB 文件或者 AOF 文件。

    将普通 Redis 服务器使用的代码替换成 Sentinel 专用代码。

    第二个步骤就是将一部分普通 Redis 服务器使用的代码替换成 Sentinel 专用代码。

    比如说, 普通 Redis 服务器使用 redis.h/REDIS_SERVERPORT 常量的值作为服务器端口:

    #define REDIS_SERVERPORT 6379
    

    而 Sentinel 则使用 sentinel.c/REDIS_SENTINEL_PORT 常量的值作为服务器端口:

    #define REDIS_SENTINEL_PORT 26379

    为什么在 Sentinel 模式下, Redis 服务器不能执行诸如 SET 、 DBSIZE 、 EVAL 等等这些命令 —— 因为服务器根本没有在命令表中载入这些命令。

    初始化 Sentinel 状态。

    在应用了 Sentinel 的专用代码之后, 接下来, 服务器会初始化一个 sentinel.c/sentinelState 结构(后面简称“Sentinel 状态”), 这个结构保存了服务器中所有和 Sentinel 功能有关的状态 (服务器的一般状态仍然由 redis.h/redisServer 结构保存):

    struct sentinelState {
    
        // 当前纪元,用于实现故障转移
        uint64_t current_epoch;
    
        // 保存了所有被这个 sentinel 监视的主服务器
        // 字典的键是主服务器的名字
        // 字典的值则是一个指向 sentinelRedisInstance 结构的指针
        dict *masters;
    
        // 是否进入了 TILT 模式?
        int tilt;
    
        // 目前正在执行的脚本的数量
        int running_scripts;
    
        // 进入 TILT 模式的时间
        mstime_t tilt_start_time;
    
        // 最后一次执行时间处理器的时间
        mstime_t previous_time;
    
        // 一个 FIFO 队列,包含了所有需要执行的用户脚本
        list *scripts_queue;
    
    } sentinel;

    初始化 Sentinel 状态的 masters 属性

    Sentinel 状态中的 masters 字典记录了所有被 Sentinel 监视的主服务器的相关信息:

    • 字典的键是被监视主服务器的名字。
    • 而字典的值则是被监视主服务器对应的 sentinel.c/sentinelRedisInstance 结构。

    每个 sentinelRedisInstance 结构代表一个被 Sentinel 监视的 Redis 服务器实例(instance), 这个实例可以是主服务器、从服务器、或者另外一个 Sentinel 。

    实例结构包含的属性非常多, 以下代码展示了一部分属性

    typedef struct sentinelRedisInstance {
    
        // 标识值,记录了实例的类型,以及该实例的当前状态
        int flags;
    
        // 实例的名字
        // 主服务器的名字由用户在配置文件中设置
        // 从服务器以及 Sentinel 的名字由 Sentinel 自动设置
        // 格式为 ip:port ,例如 "127.0.0.1:26379"
        char *name;
    
        // 实例的运行 ID
        char *runid;
    
        // 配置纪元,用于实现故障转移
        uint64_t config_epoch;
    
        // 实例的地址
        sentinelAddr *addr;
    
        // SENTINEL down-after-milliseconds 选项设定的值
        // 实例无响应多少毫秒之后才会被判断为主观下线(subjectively down)
        mstime_t down_after_period;
    
        // SENTINEL monitor <master-name> <IP> <port> <quorum> 选项中的 quorum 参数
        // 判断这个实例为客观下线(objectively down)所需的支持投票数量
        int quorum;
    
        // SENTINEL parallel-syncs <master-name> <number> 选项的值
        // 在执行故障转移操作时,可以同时对新的主服务器进行同步的从服务器数量
        int parallel_syncs;
    
        // SENTINEL failover-timeout <master-name> <ms> 选项的值
        // 刷新故障迁移状态的最大时限
        mstime_t failover_timeout;
    
        // ...
    
    } sentinelRedisInstance;

    创建连向主服务器的网络连接。

     Sentinel 将成为主服务器的客户端, 它可以向主服务器发送命令, 并从命令回复中获取相关的信息。

    对于每个被 Sentinel 监视的主服务器来说, Sentinel 会创建两个连向主服务器的异步网络连接:

    • 一个是命令连接, 这个连接专门用于向主服务器发送命令, 并接收命令回复。
    • 另一个是订阅连接, 这个连接专门用于订阅主服务器的 __sentinel__:hello 频道。
    为什么有两个连接?
    
    在 Redis 目前的发布与订阅功能中, 被发送的信息都不会保存在
     Redis 服务器里面, 如果在信息发送时, 想要接收信息的客户
    端不在线或者断线, 那么这个客户端就会丢失这条信息。
    
    因此, 为了不丢失 __sentinel__:hello 频道的任何信息, 
    Sentinel 必须专门用一个订阅连接来接收该频道的信息。
    
    而另一方面, 除了订阅频道之外, Sentinel 还又必须向主服务
    器发送命令, 以此来与主服务器进行通讯, 所以 Sentinel 还
    必须向主服务器创建命令连接。
    
    并且因为 Sentinel 需要与多个实例创建多个网络连接, 所以
     Sentinel 使用的是异步连接。

    接下来介绍 Sentinel 如何通过命令连接和订阅连接与被监视主服务器进行通讯。

    4.3.4、获取服务器信息

    sentinel默认每十秒钟发送一次INFO命令给主服务器,并获取信息:

    1)关于主服务器本身的信息

    2)主服务器属下所有从服务器信息

    sentinel发现主服务器有新的从服务器时,会创建相应的实例结构和命令连接,订阅连接

    4.3.5、给服务器发送消息

    4.3.6、主观下线

    指的是单个Sentinel实例对服务器做出的下线判断,即单个sentinel认为某个服务下线(有可能是接收不到订阅,之间的网络不通等等原因)。
    如果服务器在down-after-milliseconds给定的毫秒数之内, 没有返回 Sentinel 发送的 PING 命令的回复, 或者返回一个错误, 那么 Sentinel 将这个服务器标记为主观下线(SDOWN )。
    sentinel会以每秒一次的频率向所有与其建立了命令连接的实例(master,从服务,其他sentinel)发ping命令,通过判断ping回复是有效回复,还是无效回复来判断实例时候在线(对该sentinel来说是“主观在线”)。
    sentinel配置文件中的down-after-milliseconds设置了判断主观下线的时间长度,如果实例在down-after-milliseconds毫秒内,返回的都是无效回复,那么sentinel回认为该实例已(主观)下线,修改其flags状态为SRI_S_DOWN。如果多个sentinel监视一个服务,有可能存在多个sentinel的down-after-milliseconds配置不同,这个在实际生产中要注意。

    4.3.7、客观下线


    客观下线(Objectively Down, 简称 ODOWN)指的是多个 Sentinel 实例在对同一个服务器做出 SDOWN 判断, 并且通过 SENTINEL is-master-down-by-addr 命令互相交流之后, 得出的服务器下线判断,然后开启failover。
    客观下线就是说只有在足够数量的 Sentinel 都将一个服务器标记为主观下线之后, 服务器才会被标记为客观下线(ODOWN)。
    只有当master被认定为客观下线时,才会发生故障迁移。
    当sentinel监视的某个服务主观下线后,sentinel会询问其它监视该服务的sentinel,看它们是否也认为该服务主观下线,接收到足够数量(这个值可以配置)的sentinel判断为主观下线,既任务该服务客观下线,并对其做故障转移操作。
    sentinel通过发送 SENTINEL is-master-down-by-addr ip port current_epoch runid

    (ip:主观下线的服务id,port:主观下线的服务端口,current_epoch:sentinel的纪元,runid:*表示检测服务下线状态,如果是sentinel 运行id,表示用来选举领头sentinel)

    来询问其它sentinel是否同意服务下线。
    一个sentinel接收另一个sentinel发来的is-master-down-by-addr后,提取参数,根据ip和端口,检测该服务时候在该sentinel主观下线,并且回复is-master-down-by-addr,回复包含三个参数:down_state(1表示已下线,0表示未下线),leader_runid(领头sentinal id),leader_epoch(领头sentinel纪元)。
    sentinel接收到回复后,根据配置设置的下线最小数量,达到这个值,既认为该服务客观下线。
    客观下线条件只适用于主服务器: 对于任何其他类型的 Redis 实例, Sentinel 在将它们判断为下线前不需要进行协商, 所以从服务器或者其他 Sentinel 永远不会达到客观下线条件。只要一个 Sentinel 发现某个主服务器进入了客观下线状态, 这个 Sentinel 就可能会被其他 Sentinel 推选出, 并对失效的主服务器执行自动故障迁移操作。

    4.3.8、选举大哥sentinel

    一个redis服务被判断为客观下线时,多个监视该服务的sentinel协商,选举一个领头sentinel,对该redis服务进行故障转移操作。选举领头sentinel遵循以下规则:
    1)所有的sentinel都有公平被选举成领头的资格。
    2)所有的sentinel都只有一次将某个sentinel选举成领头的机会(在一轮选举中),一旦选举,不能更改。
    3)先到先得,一旦当前sentinel设置了领头sentinel,以后要求设置sentinel为领头请求都会被拒绝。
    4)每个发现服务客观下线的sentinel,都会要求其他sentinel将自己设置成领头。
    5)当一个sentinel(源sentinel)向另一个sentinel(目sentinel)发送is-master-down-by-addr ip port current_epoch runid命令的时候,runid参数不是*,而是sentinel运行id,就表示源sentinel要求目标sentinel选举其为领头。
    6)源sentinel会检查目标sentinel对其要求设置成领头的回复,如果回复的leader_runid和leader_epoch为源sentinel,表示目标sentinel同意将源sentinel设置成领头。
    7)如果某个sentinel被半数以上的sentinel设置成领头,那么该sentinel既为领头。
    8)如果在限定时间内,没有选举出领头sentinel,暂定一段时间,再选举。

    为什么要选?
    简单来说,就是因为只能有一个sentinel节点去完成故障转移。
    sentinel is-master-down-by-addr这个命令有两个作用,一是确认下线判定,二是进行领导者选举。
    过程:
    1)每个做主观下线的sentinel节点向其他sentinel节点发送上面那条命令,要求将它设置为领导者。
    2)收到命令的sentinel节点如果还没有同意过其他的sentinel发送的命令(还未投过票),那么就会同意,否则拒绝。
    3)如果该sentinel节点发现自己的票数已经过半且达到了quorum的值,就会成为领导者
    4)如果这个过程出现多个sentinel成为领导者,则会等待一段时间重新选举。

    4.3.9、转移

    1)挑一个新的主服务器

    2)把其它从服务器的主服务器改成新的

    3)把之前的主服务器改为新主服务器的从服务器

    4.3.10、怎么挑新的主服务器

    1)删除所有下线服务器

    2)删除五秒内没回复INOF命令的服务器

    3)删除数据旧的服务器(连接断开超过down-after-millseconds*10)

    4)根据优先级,选出最高的。

    4.3.11、重点提炼

     

    • Sentinel 是一个特殊模式下的 Redis 服务器, 它使用了不同的命令表, 所以 Sentinel 能使用的命令和普通服务器不同。
    • Sentinel 会读入用户指定的配置文件, 为每个要被监视的主服务器创建相应的实例结构, 并创建连向主服务器的命令连接和订阅连接, 其中命令连接用于向主服务器发送命令请求, 而订阅连接则用于接收指定频道的消息。
    • Sentinel 向主服务器发送 INFO 命令获得属下从服务器信息, 为这些从服务器创建实例结构、命令连接和订阅连接。
    • 默认 Sentinel 十秒一次向被监视的主服务器和从服务器发送 INFO 命令, 当主服务器处于下线状态, 或者 Sentinel 正在对主服务器进行故障转移操作时, Sentinel 向从服务器发送 INFO 命令的频率会改为每秒一次。
    • 对于监视同一个主服务器和从服务器的多个 Sentinel 来说, 它们会以每两秒一次的频率, 通过向被监视服务器的 __sentinel__:hello 频道发送消息来向其他 Sentinel 宣告自己的存在。
    • 每个 Sentinel 也会从 __sentinel__:hello 频道中接收其他 Sentinel 发来的信息, 并根据这些信息为其他 Sentinel 创建相应的实例结构, 以及命令连接。
    • Sentinel 只会与主服务器和从服务器创建命令连接和订阅连接, Sentinel 与 Sentinel 之间则只创建命令连接。
    • Sentinel 以每秒一次的频率向实例(包括主服务器、从服务器、其他 Sentinel)发送 PING 命令, 并根据实例对 PING 命令的回复来判断实例是否在线
    • 当 Sentinel 将一个主服务器判断为主观下线时, 它会向同样监视这个主服务器的其他 Sentinel 进行询问, 看它们是否同意这个主服务器已经进入主观下线状态。
    • 当 Sentinel 收集到足够多的主观下线投票之后, 它会将主服务器判断为客观下线, 并发起一次针对主服务器的故障转移操作。

     

    展开全文
  • 缘起:几年前,小儿出生的几天之内,我需要为他起名字。名字很重要吗 一文中我... 姓名五行生克法: 在数理中包含有五行生克的原理,故以数理来剖析姓名时,必须把各数理所属的五行要素辨认清楚。  在辩认五行时,只
  • JAVA 实现汉字五行笔画查询

    千次阅读 2014-02-08 11:04:02
    缘起:几年前,小儿出生的几天之内,我需要为他...姓名五行生克法: 在数理中包含有五行生克的原理,故以数理来剖析姓名时,必须把各数理所属的五行要素辨认清楚。 在辩认五行时,只计l——10的数,超过10的数,就去掉
  • 央行数字货币(数字人民币)DCEP

    千次阅读 多人点赞 2020-11-09 10:45:23
    支付清算系统重平衡 中国人民银行有大支付清算系统 大额实时支付系统(HVPS)能够为银行业金融机构和金融市场提供快速、高效、安全、可靠的清算服务,有力支持了人民币跨境支付业务,实现了跨资金清算零在途。...
  • 10万208道Java经典面试题总结(附答案)

    万次阅读 多人点赞 2021-08-01 16:05:55
    关注公众号【哪吒编程】,回复 面试题 ,获取《10万208道Java经典面试题总结(附答案)》pdf,背题更方便,一文在手,面试我有 前言 最近有很多粉丝问我,有什么方法能够快速提升自己,通过阿里、腾讯、字节跳动、...
  • 认识mysql数据库 MySQL是最流行的关系型数据库管理系统 安装mysql 关于数据库的一些概念 数据库 Database 数据表 Tables 数据字段 row 列 2.安装MySQL Mac系统中安装MySQL 使⽤用Mac中的Homebrew进⾏行行mysql的...
  • 五行属性查询

    千次阅读 2011-08-24 18:02:06
    纳音五行 五行发生演化,有了更细致的分类,出现纳音五行: 纳音五行表=甲子乙丑海中金;丙寅丁卯炉中火;戊辰己巳大林木;庚午辛未路旁土;壬申癸酉剑锋金;甲戌乙亥山头火;丙子丁丑涧下水;戊寅己卯城头土;...
  • 意思就是把一堆类型相同的数据或者字符能够放在一个变量符号里面,不用在每次写程序的时候把各种各样不同的数据都找出来写进去,只需要写这个变量符号进行表示就,这样精简了程序。为了能够表示不同的数据类型和...
  • C++套接编程基础知识介绍

    千次阅读 2019-04-14 17:00:08
    无论在Windows平台还是Linux平台,都对套接实现了自己的一套编程接口。Windows下的Socket实现叫WindowsSocket。Linux下的实现有两套:一套是伯克利套接口,起源于BerkeleyUnix,这套接口很简单,得到了广泛应用,...
  • 文献调研——算一体的一些基础知识

    千次阅读 多人点赞 2020-03-14 18:19:10
    Part 1 算一体的相关概念 Part 2 SSD基本结构 一、Why 人工智能芯片: 边缘市场-终端推理手机,可穿戴智能家居 要求低成本低功耗 -推理芯片 云端市场-云端计算、云端推理 服务器 算力大 不care成本和功耗-训练芯片...
  • 5万、97 张图总结操作系统核心知识点

    万次阅读 多人点赞 2020-07-14 09:19:25
    存储器分为两种,一种是主存,也就是内存,它是 CPU 主要交互对象,还有一种是外,比如硬盘软盘等。下面是现代计算机系统的存储架构 输入设备:输入设备是给计算机获取外部信息的设备,它主要包括键盘和鼠标。 ...
  • 数据表的基本操作 2.1 创建数据表 2.2 查看数据表 2.3 修改数据表 2.4 删除数据表 、数据表的约束 1.主键约束 2.非空约束 3.默认值约束 5.唯一性约束 6.外键约束 6.1 数据一致性概念 6.2 删除外键 6.3 关于外键...
  • 借汉诺塔理解栈与递归 单调栈 双端单调队列 单调队列优化的背包问题 01背包问题 完全背包问题 多重背包问题 串的定长表示 串的堆分配实现 KMP 一、引子 二、分析总结 三、基本操作 四、原理 、复杂度分析 ...
  • 在此之前的8月份,福布斯就有报道,曾任中国建设银行全球财务战略总监的保罗•舒尔特和一名参与央行数字货币项目的匿名人士透露,央行正向阿里巴巴、腾讯、工农中建、银联家银行机构和一家不知名实体提供其第一轮...
  • 1. TEXT TEXT有4有类型: TINYTEXT 256bytes TEXT 64kb ...3. 当你把文章进去之后,会发现使用 文章中包含 换符 之后的文字都不见了,其实他里面的数据还是有的,为了方便我把换符都换为了
  • 其中Data部分起始部分是为空值的条目建立的bitmap,仅针对可为null的column,对于主键是没有这个的,bitmap就是以那些值为null的RowId建立起来的位图,这样Data中就不用这些空值。data部分不同的column类型文件会...
  • 一丁七万丈三上下不与丐丑专且丕世丘丙业丛东丝丞丢两严丧个丫中丰串临丸丹为主丽举乂乃久么义之乌乍乎乏乐乒乓乔乖乘乙乜九乞也习乡书乩买乱乳乾了予争事二亍于亏云互亓井亘亚些亟亡亢交亥亦产亨亩享京亭亮亲亳亵...
  • .text1 { width:200px; overflow:hidden; text-overflow:ellipsis; -o-text-overflow:ellipsis; -webkit-text-overflow:ellipsis; -moz-text-overflow:ellipsis; white-space:nowrap;... width:200p
  • 本篇介绍数字的自动分割。将每的数字单独分割出来才能够一个一个识别。...将每个矩形切割出来,并单独为一个图像 旋转后的图片如图,一共有4,这里就只贴一了。 分割后的数字图片如图: 2
  • 超硬核!操作系统学霸笔记,考试复习面试全靠它

    万次阅读 多人点赞 2021-03-22 18:43:49
    活动态和静止态最本质的区别为活动态在内存中,静止态暂时调出内存,进入外 (3由执行态可以直接变为静止就绪态,即时间片用完,直接调离内存 (4)静止态(外)必须通过激活变为非静止态(调入内存)才能够参与...
  • Python-一输入多个数,并存入列表

    万次阅读 多人点赞 2020-05-19 11:08:19
    输入多个数,并存入列表
  • 超硬核!数据结构学霸笔记,考试面试吹牛就靠它

    万次阅读 多人点赞 2021-03-26 11:11:21
    算法个特性: 有穷性:有穷的时间内完成,或者可以说是可接受的时间完成 确定性:对于相同的输入只能得到相同的输出 可行性:描述的操作都可以执行基本操作有限次来实现 输入:零个或多个输入。取自于某个特定...
  • 栈的特点是存取速度快,但所数据的大小和生存期必须是确定的(编译后就已经确定大小) 堆:堆中主要存储实例化的对象和数组。线程共享。堆的优势是可以动态的分配内存大小,生存期也不必事先告诉编译器,但缺点是...
  • MySQL 服务器上负责对表中数据的读取和写入工作的部分是存储引擎,比如 InnoDB、MyISAM、Memory 等等,不同的存储引擎一般是...首先我们来看看 InnoDB 表的一数据是如何存储的。InnoDB是一个持久化的存储引擎,也就是
  • 有哪些让程序员受益终生的建议

    万次阅读 多人点赞 2019-10-28 07:11:59
    从业年多,辗转两个大厂,出过书,创过业,从技术小白成长为基层管理,联合几个业内大牛回答下这个问题,希望能帮到大家,记得帮我点赞哦。 敲黑板!!!读了这篇文章,你将知道如何才能进大厂,如何实现财务自由...
  • c程序设计第版谭浩强课后答案 第三章习题答案

    千次阅读 多人点赞 2020-07-01 10:43:33
    c程序设计第版谭浩强课后习题答案 第三章 最简单的C程序设计 ----顺序程序设计 1、假如我国国民生产总值的年增长率为7%, 计算10年后我国国民生产总值与现在相比增长多少百分比。计算公式为p=(1+r)np = (1+r)^np=...
  • 动态规划解决数字三角形

    千次阅读 多人点赞 2020-03-18 16:21:30
    由已知推未知大法 算法思想: 由上面可以看出,最优解的二维数组的最后一就是原来数组的最后一的值,而且一个元素都是可以由该元素的正下方元素和右下方元素推出来,刚好可以根据最后一层元素,层层递推,...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 102,156
精华内容 40,862
关键字:

存字的五行