前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >面试官最爱问的自旋锁,你真的懂了吗?一文带你从入门到精通

面试官最爱问的自旋锁,你真的懂了吗?一文带你从入门到精通

作者头像
早起的鸟儿有虫吃
发布于 2025-05-21 12:56:08
发布于 2025-05-21 12:56:08
9700
代码可运行
举报
运行总次数:0
代码可运行
面试官:你知道什么是自旋锁?

我能说不知道吗,我只能说知道

面试官:伸手一摆,说说你理解

大部分项目都使用互斥锁,遇到阻塞时不会占用CPU,狗都不使用...

各位老师好,我是小义,喜欢研究一些没有用的底层技术知识。

本文是大厂面试拆解第6篇文章,主要详细描述:

  1. 三种不同类型自旋锁的实现和使用场景
  2. 自旋锁的主要技术要点:原子操作和公平性,并结合C++11用户态的实现进行分析
自旋锁发展
自旋锁发展

希望在无锁编程方面对你有帮助。

一、整体面试回顾

时间:2025年4月28日 岗位:数据库开发工程师 形式:线下

一面

基础面试:

  1. 谈谈你对自旋锁的理解
  2. 进程通信的方式
  3. 线程局部存储
  4. read/write IO过程

项目面试:

  1. 干了这么多年,你的角色是什么,是开发吗?
  2. 假如让你独立开发C++特性,能不能做?
  3. 熟悉英语吗?开源社区参与中文的还是英文的,英文资料阅读能力如何?
  4. 你学校主任是谁?
  5. 在之前公司主要负责什么项目?

二、青铜(工作1-3年)怎么回答的:谈谈你对自旋锁的理解

这个题目之前我准备过,参考了以下书籍:

  • UNIX环境高级编程
  • UNIX网络编程
  • 深入理解Linux内核
  • 深入理解计算机操作系统
  • 陈硕老师Linux高性能服务器编程
  • Linux多线程服务端编程:使用muduo C++网络库

当初学习时,快速翻页,囫囵吞枣,现在很多细节都记不清楚了。 不过现在不是后悔的时候,需要快速调整心态。

回答如下:

自旋锁常用于高并发场景下,相比互斥锁:

  1. 通过循环占用CPU,为了防止中断,需要禁用中断
  2. 没有锁队列,仅用一个整数表示当前是否加锁状态
  3. 在多线程竞争情况下,保证原子性
  4. 了解C++11提到的新特性Compare-and-Swap (CAS),但理解不够深入,没有展开说明

点评:这个题目有陷阱,"谈谈xxx"不是发散题目, 而是需要聚焦使用场景和采用的技术。看到资料都是10年前的, 而且学习过程中没有完全理解,对10年后的发展了解不够。

多个人竞争一个自旋锁时存在以下问题:

  • CPU性能差异导致的不公平:就像跑步比赛,腿长腿短会影响结果(CPU性能差异)
  • 缓存命中率影响:就像排队时玩手机,注意力不集中就会错过叫号(缓存未命中) 这些问题如果处理不好就会影响系统性能,需要合理解决。
Linux自身发展
自旋锁发展历史
自旋锁发展历史

自旋锁发展历史

这个技术适用的场景
这个技术适用的场景

这个技术适用的场景

  1. 传统的自旋锁(Spinlock)满足比较并交换(Compare and Swap,CAS)/TAS(Test and Set)特性。Linux 2.0.0(1996年6月9日)从单CPU发展到对称多处理(SMP),用于解决并发竞争问题。缺点是无法保证公平性,可能导致饥饿现象。
  2. 票证自旋锁(Ticket Spinlock)于2008年12月17日发布,在2.6.26版本中正式将票据自旋锁作为默认可选的公平锁机制。其业务原理采用取号、叫号机制,通过C++11提供的内存模型和原子操作实现。缺点是当CPU数据量巨大且竞争激烈时,自旋锁状态数据对应的cacheline会在不同CPU间频繁跳动,从而影响性能。就像银行叫号系统,当2号客户业务办理完成后,需要叫3号客户,而所有排队的客户(4号、5号...甚至20号)都需要监听叫号。
  3. 可扩展锁MCS(Mellor‑Crummey and Scott)是一种基于链式队列的自旋锁算法,最早发表于1991年。它解决了传统自旋锁在多处理器系统中因所有处理器自旋在同一缓存行而导致的缓存抖动和可扩展性差等问题。Linux内核从3.12版本开始在x86_64平台采用qspinlock(queued spinlock),其慢路径即基于MCS算法。

现代高性能并发库和语言运行时(如Java并发包中的AbstractQueuedSynchronizer)也普遍采用MCS或类似的链式队列锁实现,以提升多核环境下的锁性能。

不同开源平台如何使用自旋锁(用户态)

应用示例:

  1. 在3FS代码库中,使用自旋锁(folly::SpinLock)用于统计和监控相关的场景

二、王者(工作5-10年)怎么回答的:谈谈你对自旋锁的理解

思考要点:

  1. 即使了解底层实现,也不会主动从汇编和内核角度回答,除非面试官特别提问。避免给自己制造麻烦。
  2. 从内核原理、业务框架和C++特性的统一性角度来回答。

我的理解如下:

自旋锁是一种低延时场景下的多线程同步机制,采用自旋等待(Busy‑Waiting)方式。

技术要点:

  1. 采用比较并交换等原子技术设置状态变化,由C++内存模型保证原子性
  2. 在加锁失败情况下,通过退避算法/Ticket Lock/Queue Lock避免CPU空转
  3. 优化方式:
    • 纯用户态实现:与std::mutex等基于futex的互斥量不同,自旋锁完全通过原子指令实现,无需进入内核态
    • 无阻塞上下文切换:由于没有阻塞或唤醒操作,不存在内核调度开销,适用于对延迟敏感且持锁时间极短的场景

从cpu角度解释:自旋锁怎么实现的(非系统调用 指令层面实现)

https://compiler-explorer.com/z/8v9E5vjYv

汇编解释
汇编解释

汇编解释

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
.LBB0_1:
    cmp     dword ptr [rbp - 4], 10000000   ; (1) 比较 i 与 10000000
    jge     .LBB0_4                        ; (2) 如果 i >= 10000000 跳出

    lea     rdi, [rip + sum1]             ; (3) 取 sum1 地址,放入 rdi 作为 this
    call    std::__atomic_base<int>::operator++()  ; (4) 调用原子自增

    mov     eax, dword ptr [rip + sum2]   ; (5) 读 sum2
    add     eax, 1                        ; (6) eax = eax + 1
    mov     dword ptr [rip + sum2], eax   ; (7) 写回 sum2

    mov     eax, dword ptr [rbp - 4]      ; (8) 读 i
    add     eax, 1                        ; (9) i = i + 1
    mov     dword ptr [rbp - 4], eax      ; (10) 写回 i

    jmp     .LBB0_1                       ; (11) 跳回循环开头

.LBB0_4:
    ; 循环结束,返回/退出

call std::__atomic_base<int>::operator++()
会展开为带 `LOCK` 前缀的读--写指令,
例如 `lock inc dword ptr [rip + sum1]`,
确保在多核环境下对该地址的操作是原子的
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
https://github.com/torvalds/linux/blob/master/arch/sh/include/asm/spinlock-cas.h

static inline void arch_spin_lock(arch_spinlock_t *lock)
{
    while (!__sl_cas(&lock->lock, 1, 0));
}

static inline unsigned __sl_cas(volatile unsigned *p, unsigned old, unsigned new)
{
    __asm__ __volatile__("cas.l %1,%0,@r0"
        : "+r"(new)
        : "r"(old), "z"(p)
        : "t", "memory" );
    return new;
}

源码解读:用户态 folly::SpinLock实现

Folly 是一个由Facebook 开源的C++ 库,旨在为大规模服务器开发提供高效的工具和组件

folly::MicroSpinLock` 是在 Folly 中为超细粒度锁场景设计的极小自旋锁,

  1. 实现为一个 POD 结构,仅占用一个字节,它通过在用户态对一个字节标志位执行原子比较-交换(CAS)来尝试获取锁,
  2. 失败后使用 detail::Sleeper 进行"退避"自旋,从而避免任何系统调用或内核阻塞,保证极低的延迟和良好的跨平台可移植性
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制

https://github.com/facebook/folly/blob/main/folly/SpinLock.h
SpinLock--->folly::MicroSpinLock 

/*
 * folly::MicroSpinLock
 * ====================
 * A really, *really* small spinlock for fine-grained locking of lots
 * of teeny-tiny data. 
 * 
 * Designed to be POD (Plain Old Data) so it can be
 * packed into other structures without extra overhead.
 *
 * 特性:
 *  1. 极小自旋锁,适用于超细粒度场景
 *  2. POD 类型,可零初始化,相当于调用 init()
 *  3. 用户态实现,无系统调用开销
 *  4. 支持动态检测工具插桩(ThreadSanitizer 等)
 */

struct MicroSpinLock {
// FREE 表示锁可用,LOCKED 表示锁已被持有
enum { FREE = 0, LOCKED = 1 };
//
// 用一个字节存储锁状态,避免使用 std::atomic<>,保持 POD 特性
//为什么用uint8_t表示 std::atomic<>? 
//这个和序列化有什么关系?怎么实现的
typedefunsignedchar           uint8_t;
uint8_t lock_; //locked? 


/**
   * 尝试获取锁,非阻塞
   * @return true: 获得锁;false: 未获得
   */
bool try_lock() noexcept {
    // 调用 xchg 将新值置为 LOCKED,返回旧值
    bool ret = (xchg(LOCKED) == FREE);
    // 插桩:记录尝试获取锁的结果,便于动态分析
    annotate_rwlock_try_acquired(
        this, annotate_rwlock_level::wrlock, ret, __FILE__, __LINE__);
    return ret;
  }

/**
   * 获取锁,阻塞自旋
   * 在持锁竞争时,会进行退避等待以降低总线抖动
   */
void lock() noexcept {
    detail::Sleeper sleeper;
    // 自旋尝试交换,如果旧值不为 FREE,表示竞争失败
    while (xchg(LOCKED) != FREE) {
      // 进入退避等待循环
      do {
        sleeper.wait();  // 调用 pause/yield 或指数退避
      } while (payload()->load(std::memory_order_relaxed) == LOCKED);
    }
    // 加锁成功,断言当前状态为 LOCKED
    assert(payload()->load() == LOCKED);
    // 插桩:记录获取锁的事件
    annotate_rwlock_acquired(
        this, annotate_rwlock_level::wrlock, __FILE__, __LINE__);
  }

/**
   * 释放锁
   * 将状态设为 FREE,并使用 release 语义保证可见性
   */
void unlock() noexcept {
    // 断言当前持锁状态
    assert(payload()->load() == LOCKED);
    // 释放锁  write
    payload()->store(FREE, std::memory_order_release);
  }

private:
/**
   * 内部:获取指向 lock_ 字段的原子指针
   */
std::atomic<uint8_t>* payload() noexcept {
    // reinterpret_cast 到 std::atomic<uint8_t>* 类型
    returnreinterpret_cast<std::atomic<uint8_t>*>(&this->lock_);
  }

/**
   * 原子交换操作,将 lock_ 原子地置为 newVal,返回旧值
   */
uint8_t xchg(uint8_t newVal) noexcept {
    returnstd::atomic_exchange_explicit(
        payload(), newVal, std::memory_order_acq_rel);
  } //A read-modify-write operation with this memory order is both an _acquire operation_ and a _release operation_
};

// 编译时断言:类型必须满足标准布局且平凡类型,以保证 POD 特性
static_assert(
    std::is_standard_layout<MicroSpinLock>::value &&
    std::is_trivial<MicroSpinLock>::value,
    "MicroSpinLock must be kept a POD type.");

  • MySQL InnoDB存储引擎 spin-lock 加锁失败遇到冲突后 也是采取sleep方式在尝试,避免空耗cpu

用c++11 实现一个Ticket spinlocks

原理:

取号,叫号机制
取号,叫号机制
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
参考:https://mfukar.github.io/2017/09/08/ticketspinlock.htm

  now_serving   next_ticket
        |             |
        V             V
... 01234567012 ...
         \___________/
           8 threads
           holding one ticket each

struct TicketSpinLock {
    /**
     * Attempt to grab the lock:
     * 1. Get a ticket number
     * 2. Wait for it
     */
    void enter() {
        /* We don't care about a specific ordering with other threads,
         * as long as the increment of the `next_ticket` counter happens atomically.
         * Therefore, std::memory_order_relaxed.
         */
        constauto ticket = next_ticket.fetch_add(1, std::memory_order_relaxed);

        while (now_serving.load(std::memory_order_acquire) != ticket) {
            spin_wait();
        }
    }

    /**
     * Since we're in the critical section, no one can modify `now_serving`
     * but this thread. We just want the update to be atomic. Therefore we can use
     * a simple store instead of `now_serving.fetch_add()`:
     */
    void leave() {
        constauto successor = now_serving.load(std::memory_order_relaxed) + 1;
        now_serving.store(successor, std::memory_order_release);
    }
 

c++ 内存模型

顺序

语义保证

开销

memory_order_relaxed

仅保证原子性,不保证与其他操作的顺序或可见性

最低

memory_order_acquire

保证此操作后续的读写不会在指令序上移到此操作之前

较低

memory_order_release

保证此操作前的读写不会在指令序上移到此操作之后

较低

memory_order_acq_rel

同时具备 acquire 和 release 语义,对应读写双向屏障

中等

memory_order_seq_cst

全局顺序一致性;在所有线程中可见操作顺序完全一致

最高

多cpu竞争下的可扩展的自旋锁

参考

  1. 英文:https://lwn.net/Articles/590243/
  2. Linux中的spinlock机制[二] - MCS Lock
  3. Linux中的spinlock机制[三] - qspinlock
  4. https://systemsresearch.io/posts/f22352cfc/

以解决在锁的争用比较激烈的场景下,cache line无谓刷新的问题,

其主要思想是让每个微调器在其各自的 per-CPU 变量上旋转,从而避免不同 CPU 之间不断的缓存行跳动。

当所有 CPU 都自旋等待同一个锁变量时,就会发生缓存行跳动,这会导致它们重复读取此变量。当一个 CPU 解锁时,此变量会被修改,从而使所有其他 CPU 的缓存行无效,然后这些 CPU 必须重新读取该变量。

这会导致性能开销。MCS 锁通过让每个 CPU 在其各自的专用变量上旋转来缓解这个问题,从而避免了对单个锁变量的争用。

先来看一下有3个以上的CPU持有或试图获取spinlock时,等待队列的全貌

每个cpu自选本地缓存
每个cpu自选本地缓存

总结

Linux 版本

时间

主要进展

自旋锁相关说明

2.0

1996

支持 SMP,BKL 引入

全局大内核锁,串行化所有内核操作,无需细粒度锁

2.2

1999

引入基础自旋锁机制

初步在某些子系统中使用 spinlock_t,开始去BKL化

2.4

2001

更广泛使用自旋锁

自旋锁与 cli/sti(关中断)结合使用,锁粒度更细

2.6

2003

高度并发与抢占内核

引入 spin_lock_irqsave() 等多种锁版本,应对复杂场景

3.x

2011

BKL 基本移除

通过细粒度自旋锁和 mutex 替代 BKL

4.2

2015

引入 qspinlock

MCS 队列自旋锁替代原始的 ticket lock,提高扩展性

5.x

2018+

NUMA、多核优化

更复杂的锁策略:退避、统计锁竞争、结合 RCU 等

锁竞争激烈、CPU 浪费严重

  • 问题:多个 CPU 自旋等待同一个锁时,会浪费大量 CPU 周期,尤其在临界区较长或锁被频繁争用的场景下。
  • 解决策略
    • 自旋退避(backoff)策略:在等待失败后加入延时,避免一直争抢总线。
    • TTAS(Test-and-Test-and-Set):减少 cache line 抖动。
    • MCS 自旋锁 → qspinlock(Linux 4.2):将等待线程链入队列,避免活锁并提高公平性

NUMA 架构下锁竞争代价高

  • 问题:在 NUMA 系统中,访问跨节点共享数据时,自旋锁导致 cache 频繁失效,性能下降。
  • 解决策略
    • MCS 队列锁:按顺序获取,减少 cache 抖动。
    • qspinlock(从 4.2 起默认使用):结合 MCS 与 ticket lock 的优点,兼顾低延迟与扩展性。

课后作业 无锁队列的实现

参考:https://coolshell.cn/articles/8239.htm

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2025-05-19,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 后端开发成长指南 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
一个小公司的技术开发心酸事(已倒闭)
长话短说,就是在2022年6月的时候加入了一家很小创业公司。老板不太懂技术,也不太懂管理,靠着一腔热血加上对实体运输行业的了解,加上盲目的自信,贸然开始创业,后期经营困难,最终散伙。
程序员皮皮林
2024/11/04
810
一个小公司的技术开发心酸事(已倒闭)
推荐一款拥有31.4k Star的后台管理系统!
🐯 平台简介 芋道,以开发者为中心,打造中国第一流的快速开发平台,全部开源,个人与企业可 100% 免费使用。 架构图 管理后台的 Vue3 版本采用 vue-element-plus-admin ,Vue2 版本采用 vue-element-admin 管理后台的移动端采用 uni-app 方案,一份代码多终端适配,同时支持 APP、小程序、H5! 后端采用 Spring Boot、MySQL + MyBatis Plus、Redis + Redisson 数据库可使用 MySQL、Oracle、Pos
程序猿DD
2023/04/04
2K0
推荐一款拥有31.4k Star的后台管理系统!
小程序开发框架对比(wepy/mpvue/uni-app/taro)
uni-app 团队投入两周完成了这个深度评测,下面我们就分享下,实际开发不同框架的测试例时遇到的问题,以及在各端的兼容测试结果。在本文里,我们团队基于真实测试数据及各框架官网可采集到的公开数据,希望客观公正地评价各个框架的选型和优劣。但宥于利益相关,本文的观点很可能是带有偏向性的,大家可以带着批判的眼光去看待。
码客张
2019/04/24
6.3K0
Node全栈为前端带来更多可能
2017年,Node.js最大的变化是进入Node 8时代,它是一个稳定的长期支持版本(LTS),除了性能提升外,还有以下几个要点。 Async/Await支持。其实在Node.js v7.6就可以通
用户1263954
2018/05/30
1.1K0
打算一个卡片记忆软件,全平台架构如何选型?
折腾来折腾去,我打算做一个卡片记忆软件,用来记忆面试题、知识点等。很多东西看了就忘了,我想做一个软件来帮助我记忆。这个软件的功能就是每天给我推送一些卡片,我看了就可以记住,然后就可以刷题了。
程序员朱永胜
2023/11/23
5580
打算一个卡片记忆软件,全平台架构如何选型?
社交APP开发的技术框架
一个典型的社交APP会包含前端(移动APP或Web端)、后端(服务器、数据库)以及一些支持工具和服务。
数字孪生开发者
2025/05/28
1050
社交APP开发的技术框架
真实测评揭秘:开发小程序用原生还是选框架?
自 2017-1-9微信小程序诞生以来,历经几年的迭代升级,已有数百万小程序上线,成为继Web、iOS、Android之后,第四大主流开发技术。
极乐君
2020/05/26
6.9K1
真实测评揭秘:开发小程序用原生还是选框架?
真实测评:用uni-app开发小程序,比原生开发好用在哪里?
原生wxml开发对Node、预编译器、webpack支持不好,影响开发效率和工程构建流程。所以大公司都会用框架开发
极乐君
2020/06/10
11.3K0
小程序框架选型必看:Taro vs uni-app选型经历!
公司新产品要求发布到各家小程序,最近研究对比了社区主流的几家小程序开发框架,独坑不如拉人众坑,分享给各位,欢迎和我一起入坑:)
极乐君
2020/05/22
14K1
小程序框架选型必看:Taro vs uni-app选型经历!
选择大公司还是小公司?我来回答你
就是这位学妹 昨天有位应届生学妹问我,她现在拿到了两家公司的实习offer,一个是一家创业公司,公司技术有6人,月薪8k;另一家是大一点的传统型企业,技术部门大概有100来人,月薪7.5k。她应该怎么选择?好吧,我的文章基本都来自生活中的一些事,请听我讲讲。 我们先来谈谈大小公司的优点。 大公司:可以观察、学习比较成熟的企业文化和运营流程;同时大公司一般会专门指派一个导师来帮助你,有些还会有很多针对新人的培训项目;还有一个就是大企业带给你带来品牌效应——职场品牌(前提是至少得是BAT这种公司)。 小公
黄小怪
2018/05/21
9450
盘点一些非常好用的小程序开发工具,包括一些低代码工具
可视化设计,有丰富的组件可以选择,直接拖拽就可以生成页面,此外, 它还提供了丰富的模板,可以直接导入使用,比如电商模板,管理模板等,可以直接使用。此外,它还提供了数据收集功能,表单的数据可以在后台直接管理查看。
程序那些事儿
2023/07/24
2K0
盘点一些非常好用的小程序开发工具,包括一些低代码工具
DNSPod十问王安:中小企业的数字化是伪命题吗?
问答时间:2020年9月24日 嘉宾简介: 王安:DCloud公司创始人,HTML5中国产业联盟秘书长。2003年开始从事移动互联网工作,十几年编程和商业经验,小程序领域专家。出品了HBuilder、uni-app等广受开发者欢迎的产品。 主持人简介: 吴洪声(人称:奶罩):腾讯云中小企业产品中心总经理,DNSPod创始人,洋葱令牌创始人,网络安全专家,域名及DNS技术专家,知名个人站长,中欧国际工商学院校友。 以下为对话原文整理: 吴洪声:你在2003年开始在从事移动互联网,那时手机才刚能写程
腾讯云DNSPod团队
2020/09/25
5810
聊一聊小程序框架
随着微信小程序的爆火,如今小程序几乎已经取代了传统的 h5 应用,成为了主流。 各大 app 都有自己的小程序,开发规范技术五花八门,作为前端开发者,若想做到在各大应用上都开发自己的小程序需要耗费巨大的精力。 似乎又回到了之前“各大浏览器共存的”兼容时代了。 好在,如今前端“基建”相当完善,大佬们很快就有了解决方案,那就是利用“编译”和“构建”,将同一套业务代码通过语法分析,然后“编译构建”出适配各个平台的小程序。 此类方案很多,我将这些方案称为“小程序开发框架”。
epoos
2023/04/01
7220
聊一聊小程序框架
未来大前端技术趋势深度解读
自Vue.js 3.0爆出,三大主流框架,写法也是越来越相似,越来越贴近 WebComponents 标准,而周边应用层面的封装已经开始指数级增长。小程序是今年最火的技术,接连出现,快应用也想分一杯羹。PWA(Progressive Web App)进入稳定期,尤其是 PWA桌面版,可以让我们更好的看清楚 PC 桌面版开发的全貌。移动端还是以强运营为主,各大公司都开始不再 全力推动 移动端了,开始重视多端并进,到了开始拼细节的阶段了。TypeScript 全面开花,GraphQL 蠢蠢欲动,WebAssembly 更是打开了浏览器上多语言的大门。所有的这一切都在暗示,浏览器即操作系统,你能想象到未来前端的样子么?
Javanx
2019/09/04
2.2K0
未来大前端技术趋势深度解读
想跨端开发小程序?这个最流行的跨端框架一定要学习!
从最早发布的微信小程序,到后来的支付宝小程序、字节跳动小程序、百度小程序、QQ小程序,还有最近发布的360小程序,面对这么多套的代码,开发者该如何开发呢?
极乐君
2020/09/16
1.7K0
想跨端开发小程序?这个最流行的跨端框架一定要学习!
前端跨平台框架对比分析,看这篇就够了
前端跨端实践是指在开发过程中,使用统一的代码库或框架来实现在不同平台上运行的应用程序。
winty
2023/08/23
6.1K0
前端跨平台框架对比分析,看这篇就够了
uni-app跨平台框架介绍和快速入门
  首先今天主要介绍的是一个多平台的前端框架uni-app,关于多平台的前端框架网上有很多成熟的解决方案比如说Taro,React Native,Flutter等这些都是一些非常优秀的前端跨平台的框架(大家想要了解更多可以上网查询各种框架的优缺点,温馨提示:没有最好的框架,选择适合自己或者自己团队的才是最好的框架)。
追逐时光者
2021/09/28
1.6K0
uni-app官方教程学习手记
大概在今年的十月份左右,我了解到Dcloud推出了uni-app。当时下载了一个Hbuilder X,下载了官方提供的hello示例教程。经过一番努力,在云端打包成功了。当时这个软件还不够完善,用iphone真机模拟运行时,还会存在中文乱码问题。我还特意提交了一个bug。
siberiawolf
2020/03/24
1.3K1
微前端从Golang开始 | 🏆 技术专题第四期
图片 确认一遍 对你没看错,微前端是从Golang开始 核心观点:所有脱离业务场景的技术讨论都是耍流氓 微前端实践过程中的感悟:juejin.cn/post/686082… 关键词:样式,事件,缓存的相互冲突,特性代码的规则方案,通信机制的建立 需求背景 新旧多系统集成 日均上xx的独立用户访问 跨多个业务部门合作方式 主要问题 前端系统多技术栈,新旧项目错综复杂,有维护了6年的jq项目,也有新加入的react项目 后端完全失控,虽然前端页面是多个后端系统集合体现,但是对于各个子系统状态一无所知 解决
吴文周
2022/09/16
2270
微前端从Golang开始 | 🏆 技术专题第四期
FinClip 与 uniapp:轻应用平台与前端开发框架
简单来说,uni-app 是一款为了解决跨端开发问题所设计的前端开发框架,开发者通过 uni-app 所编写出的一套代码,可以发布到 iOS,Android,H5 平台之中。
Onegun
2022/01/05
1.7K0
FinClip 与 uniapp:轻应用平台与前端开发框架
推荐阅读
相关推荐
一个小公司的技术开发心酸事(已倒闭)
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验