欢迎来到皮皮网网首页

【学习spring源码】【19充值源码】【新楼盘源码】once源码分析

来源:ftpserver源码c 时间:2024-11-25 02:34:30

1.Android Touch事件InputManagerService源码解析(二)
2.Rust并发:标准库sync::Once源码分析
3.Flink mysql-cdc connector 源码解析
4.onStart()和onResume()/onPause()和onStop()的区别?
5.深入理解Vue3自定义指令ClickOutside的源码实现
6.深入剖析vscode工具函数(三)once函数

once源码分析

Android Touch事件InputManagerService源码解析(二)

       解析Android Touch事件分发过程,深入InputManagerService源码。分析触摸事件的源码产生与传递机制是本文探讨的核心。

       InputDispatcher接收到事件,分析通过enqueueInboundEventLocked接口将事件放入mInboundQueue队列,源码等待分发处理。分析学习spring源码

       InputDispatcher内部线程在有事件时被唤醒,源码执行dispatchOnce,分析根据事件类型调用dispatchMotionLocked进行处理。源码处理流程涉及找到要处理事件的分析窗口。

       窗口查找通过findFocusedWindowTargetsLocked方法实现,源码该方法从map中获取focusedWindowHandle和focusedApplicationHandle,分析存储目标窗口信息。源码

       这些句柄的分析初始化在Activity的生命周期回调中,如Activity.onResume时。源码具体路径涉及ActivityTaskManagerService、DisplayContent、InputMonitor和InputManagerService。

       分发循环由prepareDispatchCycleLocked、enqueueDispatchEntryLocked和enqueueDispatchEntriesLocked方法实现,最后调用startDispatchCycleLocked,将事件发送给对应进程。

       InputReader持续从底层读取事件,19充值源码InputDispatcher通过线程处理分发,直至事件被发送至目标进程。本文深入解析了Touch事件的分发机制与关键步骤,提供了对Android触摸事件处理过程的全面理解。

Rust并发:标准库sync::Once源码分析

       一次初始化同步原语Once,其核心功能在于确保闭包仅被执行一次。常见应用包括FFI库初始化、静态变量延迟初始化等。

       标准库中的Once实现更为复杂,其关键在于如何高效地模拟Mutex阻塞与唤醒机制。这一机制依赖于线程暂停和唤醒原语thread::park/unpark,它们是实现多线程同步对象如Mutex、Condvar等的基础。

       具体实现中,Once维护四个内部状态,状态与等待队列头指针共同存储于AtomicUsize中,利用4字节对齐优化空间。

       构造Once实例时,初始化状态为Incomplete。调用Once::call_once或Once::call_once_force时,分别检查是否已完成初始化,未完成则执行闭包,新楼盘源码闭包执行路径标记为冷路径以节省资源,同时避免泛型导致的代码膨胀。

       闭包执行逻辑由Once::call_inner负责,线程尝试获取执行权限,未能获取则进入等待状态,获取成功后执行闭包,结束后唤醒等待线程。

       等待队列通过无锁侵入式链表实现,节点在栈上分配,以优化内存使用。Once::wait函数实现等待线程逻辑,WaiterQueue的drop方法用于唤醒所有等待线程,需按特定顺序操作栈节点,以避免use after free等潜在问题。

       思考题:如何在实际项目中利用Once实现资源安全共享?如何评估Once与Mutex等同步原语在不同场景下的性能差异?

Flink mysql-cdc connector 源码解析

       Flink 1. 引入了 CDC功能,用于实时同步数据库变更。Flink CDC Connectors 提供了一组源连接器,支持从MySQL和PostgreSQL直接获取增量数据,如Debezium引擎通过日志抽取实现。以下是Flink CDC源码解析的关键部分:

       首先,MySQLTableSourceFactory是实现的核心,它通过DynamicTableSourceFactory接口构建MySQLTableSource对象,成交密集源码获取数据库和表的信息。MySQLTableSource的getScanRuntimeProvider方法负责创建用于读取数据的运行实例,包括DeserializationSchema转换源记录为Flink的RowData类型,并处理update操作时的前后数据。

       DebeziumSourceFunction是底层实现,继承了RichSourceFunction和checkpoint接口,确保了Exactly Once语义。open方法初始化单线程线程池以进行单线程读取,run方法中配置DebeziumEngine并监控任务状态。值得注意的是,目前只关注insert, update, delete操作,表结构变更暂不被捕捉。

       为了深入了解Flink SQL如何处理列转行、与HiveCatalog的结合、JSON数据解析、DDL属性动态修改以及WindowAssigner源码,可以查阅文章。你的支持是我写作的动力,如果文章对你有帮助,请给予点赞和关注。

       本文由文章同步助手协助完成。

onStart()和onResume()/onPause()和onStop()的区别?

       onStart()和onResume()/onPause()和onStop()的区别?

        先看一下官方声明周期图

        这里应用场景:一般启动app:

        onCreate -onStart() - onResume

        按一下home 键:onPause-onStop

        再从其他页面返回到LoginActivtiy:

        -onNewIntent- onRestart -onStart -onResume

        2.onCeate vs onStart vs onResume

        看stackoverflow上回答:

       /questions//difference-between-oncreate-and-onstart

        onCreate :

        called when the actiivty first created,do create views bind data to list etc.

        参数Bunldel上次被异常情况销毁时保存的状态信息

        3.onStart()和onResume()/onPause()和onStop()的区别?

        onStart /onStop 从可见的角度回调的; 而onResume/onPasue 从是否位于前台的角度回调的,而在实际应用中没什么区别。

        总之,记住

        onStart 可见不可点击 onResume 可见可点击;

        onPause 可见不可点击(比如弹出对话框)

        onStop 不可见

        4.Activity A启动另一个Activity B会回调哪些方法?

        如果Activity B是完全透明呢?如果启动的是一个Dialog呢?

        一般情况,当用户打开一个新的界面或是回到桌面,回调:

        onPause -->onStop();

        如果透明:onStop()不再调用(启动一个透明主题的ActivityB,0110的源码因为ActivityA还是可见的,但不在前台,)

        当再次回到ActivityA时,会回调 onRestart () -->onStart()--->onResume();

        5.back键:

        onPause -->onStop -->onDestory;

        6.当前Actiivty是A,如果用户打开一个新的ActivityB,那么B.onRsume() 和A.onPause()哪个先回调?

        这个问题,要从源码分析。暂不详细说了,总之,源码里有一段话“we need to start pasuing the curent activity ,so the top one can be resumed"

        即先A.onPause() ,然后B.onResume()

深入理解Vue3自定义指令ClickOutside的实现

       深入理解Vue3自定义指令ClickOutside的实现

       本文深入解析自定义指令ClickOutside的实现逻辑与原理,旨在为开发者提供清晰的理解路径。通过工具函数on和off的使用,理解事件绑定与解除绑定的基本操作。此外,介绍了在naive-ui-admin源码中on和off函数的高效应用,以及如何使用它们扩展为一次性事件处理函数once。

       在自定义指令部分,解释了如何利用Vue的指令系统封装满足特定业务需求的指令,如ClickOutside。通过分析指令对象的生命周期钩子函数,特别是mounted、updated和beforeUnmount,以及参数el和binding的作用,展示了指令的定义与使用方式。

       动态参数指令arg的介绍,展示了如何通过指令参数arg实现动态参数的切换,以适应不同的业务需求。利用arg属性,自定义指令可以更灵活地应对不同的场景。

       简易版本实现中,首先定义了指令的事件处理函数eventHandler,并将其绑定到document上。通过判断事件target是否在el元素内,执行对应的处理逻辑。其中,contains函数用于判断节点关系,同时通过el === e.target的判断确保不误触发事件。简易版本最终实现了一个基本的ClickOutside功能。

       针对简易版本的优化,提出将事件绑定到document上,仅在初始化和移除指令时执行,以减少每次绑定和解绑的操作。通过使用Map对象收集所有指令的eventHandler函数,在触发事件时统一执行,同时解决了解绑时寻找每个el对应函数的问题。

       升级优化部分,通过对比VueUse和element-plus的实现逻辑,发现点击事件的触发机制不同,从而改进了简易版本,使其支持鼠标左、中、右键触发。进一步分析了click、mouseup和mousedown事件的区别,使得简易函数能够适应更广泛的用例。

       源码实现逻辑中,详细介绍了naive-ui-admin中ClickOutside指令的实现细节。除了createDocumentHandler函数,其他功能与简易版本的实现相似,关键在于通过匿名闭包引用el和binding,实现指令与事件处理的联动。重点关注createDocumentHandler函数内部的逻辑,以及六个判断条件的使用,确保只有满足特定条件时才会触发对应的处理逻辑。

       总结部分,本文旨在为读者提供一个全面的Vue3自定义指令ClickOutside实现的理解框架,从基本概念到源码细节,逐步深入解析。理解ClickOutside的实现逻辑有助于开发者在实际项目中灵活应用,解决与元素点击范围相关的复杂场景。

深入剖析vscode工具函数(三)once函数

       深入解析VSCode工具函数:once函数

       once函数在JavaScript编程,特别是函数式编程中扮演着重要角色,它解决了在多次调用同一函数时避免冗余计算的问题。这种函数只允许执行一次,然后返回结果,显著提升性能并保持代码简洁。

       在lodash等现代库中,once函数是标准提供,如其源码中,通过before函数的封装实现,利用闭包机制来判断函数是否已调用过,确保函数的单次执行。在VSCode这样的工具中,once的使用频率非常高,可以观察到许多代码引用。

       在应用时,once函数适用于需要确保函数只运行一次的场景,如缓存结果、避免重复网络请求或执行一次性的初始化操作。然而,使用时需注意原始函数中的this关键字,因为它可能被内部保存的变量替换。不正确的this绑定可能导致意外错误或异常,因此确保this正确绑定至关重要。

       总的来说,once函数为开发人员提供了一种优雅且高效的解决方案,避免了传统方法中繁琐的控制变量,是提高代码可维护性和性能的实用工具。

从项目的一个 panic 说起:Go 中 Sync 包的分析应用

       在项目开发过程中,遇到一个常见的错误——"fatal error: concurrent map read and map write",这是由于Golang内建的map在并发环境下不安全导致的。解决这个问题的方法并不复杂,就是转向使用sync包提供的并发安全的map。

       sync包在Golang 1.9之后被官方支持,其中包含了丰富的同步原语,是并发编程的关键部分。在Golang 1.9之前,解决map并发问题通常会借助sync包中的sync.RWMutex或其他锁机制。Golang作为支持用户态进程的编程语言,对并发编程的处理自然离不开锁,这是一种确保多个Goroutine在同一片内存中协同工作的同步机制。

       sync包的源码目录结构清晰,包含Mutex、RWmutex、WaitGroup、Map、Once、Cond、Pool等组件。接下来,我们将逐个分析这些同步原语的用途和使用注意事项,重点讨论在项目中常见的sync.Map。

       sync.Map是sync包中的一种高效并发安全的map实现,与内建map相比,它提供了Load、Store、LoadOrStore、Delete和Range等方法,并且具有更高的并发性能。虽然sync.Map没有len方法,但其内部机制使得在并发环境中的操作更加稳健。

       通过结合实际项目案例和面试题中的陷阱,本文简要探讨了sync包中Mutex、RWMutex、WaitGroup、Once以及Map的使用技巧和注意事项。在实际编程中,正确使用这些同步原语对于避免并发问题至关重要。

Go并发编程 — sync.Once

       ç®€ä»‹

       Once 可以用来执行某个函数,但是这个函数仅仅只会执行一次,常常用于单例对象的初始化场景。说到这,就不得不说一下单例模式了。

单例模式

       å•ä¾‹æ¨¡å¼æœ‰æ‡’汉式和饿汉式两种,上代码。

饿汉式

       é¥¿æ±‰å¼é¡¾åæ€ä¹‰å°±æ˜¯æ¯”较饥饿,所以就是上来就初始化。

var?instance?=?&Singleton{ }type?Singleton?struct?{ }func?GetInstance()?*Singleton?{ return?instance}懒汉式

       æ‡’汉式顾名思义就是偷懒,在获取实例的时候在进行初始化,但是懒汉式会有并发问题。并发问题主要发生在 instance == nil 这个判断条件上,有可能多个 goruntine 同时获取 instance 对象都是 nil ,然后都开始创建了 Singleton 实例,就不满足单例模式了。

var?instance?*Singletontype?Singleton?struct?{ }func?GetInstance()?*Singleton?{ if?instance?==?nil?{ ?instance?=?&Singleton{ }}return?instance}加锁

       æˆ‘们都知道并发问题出现后,可以通过加锁来进行解决,可以使用 sync.Metux 来对整个方法进行加锁,就例如下面这样。这种方式是解决了并发的问题,但是锁的粒度比较高,每次调用 GetInstance 方法的时候都需要获得锁才能获得 instance 实例,如果在调用频率比较高的场景下性能就不会很好。那有什么方式可以解决嘛?让我们接着往下看吧

var?mutex?sync.Mutexvar?instance?*Singletontype?Singleton?struct?{ }func?GetInstance()?*Singleton?{ mutex.Lock()defer?mutex.Unlock()if?instance?==?nil?{ ?instance?=?&Singleton{ }}return?instance}Double Check

       ä¸ºäº†è§£å†³é”çš„粒度问题,我们可以使用 Double Check 的方式来进行解决,例如下面的代码,第一次判断 instance == nil 之后需要进行加锁操作,然后再第二次判断 instance == nil 之后才能创建实例。这种方式对比上面的案例来说,锁的粒度更低,因为如果 instance != nil 的情况下是不需要加锁的。但是这种方式实现起来是不是比较麻烦,有没有什么方式可以解决呢?

var?mutex?sync.Mutexvar?instance?*Singletontype?Singleton?struct?{ }func?GetInstance()?*Singleton?{ if?instance?==?nil?{ ?mutex.Lock()?defer?mutex.Unlock()?if?instance?==?nil?{ ?instance?=?&Singleton{ }?}}return?instance}使用 sync.Once

       å¯ä»¥ä½¿ç”¨ sync.Once 来实现单例的初始化逻辑,因为这个逻辑至多只会跑一次。推荐使用这种方式来进行单例的初始化,当然也可以使用饿汉式。

var?once?sync.Oncevar?instance?*Singletontype?Singleton?struct?{ }func?GetInstance()?*Singleton?{ once.Do(func()?{ ?instance?=?&Singleton{ }})return?instance}源码分析

       ä¸‹é¢å°±æ˜¯ sync.Once 包的源码,我删除了注释,代码不多,Once 数据结构主要由 done 和 m 组成,其中 done 是存储 f 函数是否已执行,m 是一个锁实例。

type?Once?struct?{ done?uint?//?f函数是否已执行mMutex?//?锁}func?(o?*Once)?Do(f?func())?{ if?atomic.LoadUint(&o.done)?==?0?{ ?o.doSlow(f)}}func?(o?*Once)?doSlow(f?func())?{ o.m.Lock()defer?o.m.Unlock()if?o.done?==?0?{ ?defer?atomic.StoreUint(&o.done,?1)?f()}}

       Do 方法

       ä¼ å…¥ä¸€ä¸ª function,然后 sync.Once 来保证只执行一次,在 Do 方法中使用 atomic 来读取 done 变量,如果是 0 ,就代码 f 函数没有被执行过,然后就调用 doSlow方法,传入 f 函数

       doShow 方法

       doShow 的第一个步骤就是先加锁,这里加锁的目的是保证同一时刻是能由一个 goruntine 来执行 doSlow 方法,然后再次判断 done 是否是 0 ,这个判断就相当于我们上面说的 DoubleCheck ,因为 doSlow 可能存在并发问题。然后执行 f 方法,然后执行使用 atomic 将 done 保存成 1。使用 DoubleCheck 保证了 f 方法只会被执行一次。

       æŽ¥ç€çœ‹ï¼Œé‚£å¯ä»¥è¿™æ ·å®žçŽ° sync.Once 嘛?

       è¿™æ ·ä¸æ˜¯æ›´ç®€å•ä¸€ç‚¹å˜›ï¼Œä½¿ç”¨åŽŸå­çš„ CAS 操作就可以解决并发问题呀,并发只执行一次 f 方法的问题是可以解决,但是 Do 方法可能并发,第一个调用者将 done 设置成了 1 然后调用 f 方法,如果 f 方法特别耗时间,那么第二个调用者获取到 done 为 1 就直接返回了,此时 f方法是没有执行过第二次,但是此时第二个调用者可以继续执行后面的代码,如果后面的代码中有用到 f 方法创建的实例,但是由于 f 方法还在执行中,所以可能会出现报错问题。所以官方采用的是Lock + DoubleCheck 的方式。

if?atomic.CompareAndSwapUint(&o.done,?0,?1)?{ f()}拓展

       æ‰§è¡Œå¼‚常后可继续执行的Once

       çœ‹æ‡‚了源码之后,我们就可以扩展 sync.Once 包了。例如 f 方法在执行的时候报错了,例如连接初始化失败,怎么办?我们可以实现一个高级版本的 Once 包,具体的 slowDo 代码可以参考下面的实现

func?(o?*Once)?slowDo(f?func()?error)?error?{ o.m.Lock()defer?o.m.Unlock()var?err?errorif?o.done?==?0?{ ?//?Double?Checkerr?=?f()if?err?==?nil?{ ?//?没有异常的时候记录done值atomic.StoreUint(&o.done,?1)}}return?err}

       å¸¦æ‰§è¡Œç»“果的 Once

       ç”±äºŽ Once 是不带执行结果的,我们不知道 Once 什么时候会执行结束,如果存在并发,需要知道是否执行成功的话,可以看下下面的案例,我这里是以 redis 连接的问题来进行说明的。Do 方法执行完毕后将 init 值设置成 1 ,然后其他 goruntine 可以通过 IsConnetion 来获取连接是否建立,然后做后续的操作。

type?RedisConn?struct?{ once?sync.Onceinit?uint}func?(this?*RedisConn)?Init()?{ this.once.Do(func()?{ ?//?do?redis?connection?atomic.StoreUint(&this.init,?1)})}func?(this?*RedisConn)?IsConnect()?bool?{ ?//?另外一个goroutinereturn?atomic.LoadUint(&this.init)?!=?0}