小天管理 发表的所有内容
-
原本约好一起出来看柯南大电影的 结果突然莫名其妙被拉黑了 隐藏了所有加好友的方式 现在只有个分享名片出去 发送了申请但之后就把名片添加的方式也设置了不能添加 之前有个强制加好友的代码 但实验后貌似对方是收不到好友申请的 求求 v2 大神了 明天就要看电影了
-
欢迎全栈开发者加入本群! 这里是各路编程高手的技术交流平台,涵盖了多种主流编程语言和技术栈。 无论你专注于前端(如 HTML 、CSS 、JavaScript 、TypeScript )、后端(如 Java 、Python 、PHP 、Go 、Node.js 、Ruby 、C#)、移动端(如 Swift 、Kotlin 、Flutter 、React Native )、数据库(如 SQL 、NoSQL 、MongoDB 、PostgreSQL )、还是DevOps(如 Docker 、Kubernetes 、CI/CD ),都可以在这里分享经验、交流技 telegram: 链接 1 telegram: 链接 2
-
看网上直通核显给 win 似乎有点麻烦呢?那其他硬件呢?还能像物理机跑 win 那么丝滑吗? 最近手贱想折腾折腾 ,请大佬赐教! 233
-
最近一个项目要用到大文件的断点续传,多大文件呢,大的包可能会有 20G ,目前的做法是 前端取到文件后,按 2m 一个片段进行分片,然后逐个上传 后端收到完整的文件后放在一个隐藏的目录内,等最后的文件传完之后,逐一合并,并移动到指定的文件夹 实现是实现了,最大的问题不是上传,而是合并以及转移文件相当消耗时间 有没有更高级的做法呢?
-
之前上线了款 APP(Tiny Clicker),发兑换码+App Store 购买,销量破百了🎉 最近刷 X 看到有大佬(Guy Dupont)用鼠标做了个类似以前 DVD 机器待机屏保的推文,就抄过来做了个防止 Mac 进入休眠状态、调暗屏幕或启动常规屏保的 App ,额外又增加了个通过快捷键快速切换屏幕的功能(: D)。 🌟 App 链接:NinjaCursor 提供几个兑换码供 V 友使用。请尽快领取,数量有限哦! 兑换码: LL4YMEJ3K7FR FYJR93YMAX4N KWP643FTYM74 6JRKATMJ6MAM PAFFHTEHENKT WPA7WTR6XR3H L7FE3ETFHFF9 KFWNEWX77LP6 AHNRFA97H36L XRJJ4WFPXP6F YYA74W4M3N7P AYE9RLE966H4 4PYNN63KT9PN ELHJ6AWPRLLM HKTWXF99TP74
-
在 React 世界里,useEffect 和 useState 无疑是最常见的钩子( Hooks ),它们让函数组件拥有了类组件的力量。useState 赋予了组件维护状态的能力,而 useEffect 则让副作用管理变得简单。 对许多开发者来说,上述两个 Hooks 是 React 钩子的入门级应用,但随着项目复杂度的提升,仅仅使用这两个钩子可能会让组件变得臃肿,逻辑复杂难以维护。此时,众多开源社区的 React Hooks 库应运而生,它们提供了许多高质量、语义化的 Hooks ,帮助开发者更好地管理组件状态、副作用等,提升代码质量。@shined/react-use 就是这样一款优秀的 React Hooks 库。 本文旨在充分利用 @shined/react-use 提供的 Hooks ,呈现一份全面的基于 React Hooks 的代码质量提升指南,引导你走出 useEffect 和 useState 的舒适区,发掘 React Hooks 的真正潜力和灵活性,提升项目代码质量。 替换 useState useState 是 React 中用来管理组件状态的 Hook ,基本上每个 React 开发者都会用到。 但是低版本 React 中的 useState 可能导致非预期的行为。比如在 React <= 17 时,当组件卸载后,调用 setState 会抛出令人困惑的警告(参考 安全状态)。此外,React 内部使用浅比较来判断状态是否改变,这可能会导致组件进行不必要的重渲染,从而影响性能。 useSafeState useSafeState 被设计为 useState 的直接替代方案,用于规避低版本 React 下的警告问题,并遵循官方做法在高版本 React 下与 useState 行为保持一致。 同时它还具备可选的性能优化特性(deep 选项,深度比较状态,确认变更再更新,默认 false)。 更多详情请参考 安全状态 和 useSafeState。 const [name, setName] = useState('react') // 替换为 const [name, setName] = useSafeState('react') const [state, setState] = useState({ count: 0 }) setState({ count: 0 }) // 触发重新渲染 setState({ count: 0 }) // 触发重新渲染 setState({ count: 0 }) // 触发重新渲染 // 替换为 const [state, setState] = useSafeState({ count: 0 }, { deep: true }) setState({ count: 0 }) // 不会触发重新渲染 setState({ count: 0 }) // 不会触发重新渲染 setState({ count: 0 }) // 不会触发重新渲染 // deep 为可选项,当状态简单、可控,且状态值的地址频繁变动,但实际值未改变时,将显著降低渲染次数 useBoolean useBoolean 用于管理布尔值状态,提供了一系列语意化的操作函数,例如 toggle、setTrue、setFalse 等,底层使用 useSafeState 以确保状态安全。 详情参考 useBoolean。 const [bool, actions] = useBoolean(false) actions.toggle() // true actions.setTrue() // true actions.setFalse() // false useCounter useCounter 用于管理 number 类型状态,提供了一系列语意化的操作函数,例如 inc、dec、set 等,底层使用 useSafeState 以确保状态安全。 详情参考 useCounter。 const [count, actions] = useCounter(0) actions.inc() // 1 actions.inc(10) // 11 actions.dec() // 10 actions.set(20) // 20 减少 useEffect useEffect 是 React 中最基础、最常用的 Hook 之一,但一般情况下,我们并不推荐直接使用。因为它的使用方式相对较为原始,且容易出现副作用难以控制,或副作用与预期不符等问题。 @shined/react-use 提供了一系列高质量、语意化的 Hooks 来等价替换部分 useEffect 调用场景。 useMount 我们可能会这样使用 useEffect,功能上等同于组件挂载时执行一次 doSomething()。 // 不推荐 useEffect(() => { doSomething() }, []) 或者,当我们需要在挂载时执行一些异步操作且需要拿到结时果,我们通常会包一层 async 函数来执行异步操作。 // 不推荐 useEffect(() => { async function asyncWrapper() { const result = await doSomethingAsync() const.log(result) } asyncWrapper() }, []) 以上代码在逻辑上完全没问题,但是存在代码可读性差、缺乏语意化、后期难以维护、可能意外返回清理函数等诸多问题和隐患,同时对异步函数支持不够友好。推荐替换为更加语义化的 useMount,支持异步函数。 详情参考 useMount。 // 推荐 useMount(doSomething) // 推荐 useMount(async () => { const result = await doSomethingAsync() const.log(result) }) useUnmount useUnmount 用于在组件卸载时执行一些操作,例如清理副作用,基本与 useMount 类似,但执行时机不同。 详情参考 useUnmount。 // 不推荐 useEffect(() => { return () => { doSomething() } }, []) // 推荐 useUnmount(doSomething) useUpdateEffect useUpdateEffect 用于在组件更新时执行一些操作,例如监听某些状态的变化并执行操作,但是忽略首次渲染,适用于不需要立即执行副作用的场景。 详情参考 useUpdateEffect。 // 不推荐 const isMount = useRef(false) useEffect(() => { if (isMount.current) { doSomething() } else { isMount.current = true } }, [state]) // 推荐 useUpdateEffect(() => { doSomething() }, [state]) useEffectOnce useEffectOnce 用于在组件挂载时执行一次操作,在组件卸载时也执行一次操作,适用于只需要执行一次副作用的场景,本质上 useEffectOnce 是 useMount 和 useUnmount 的组合。 详情参考 useEffectOnce。 // 不推荐 useEffect(() => { doSomething() return () => clearSomething() }, []) // 推荐 useEffectOnce(() => { doSomething() return () => clearSomething() }) useAsyncEffect useAsyncEffect 用于在状态变更时执行异步操作,适用于需要监听状态变化并执行异步操作的场景。 详情参考 useAsyncEffect。 // 不推荐 useEffect(() => { async function asyncWrapper() { const result = await doSomethingAsync() // 当前 Effect 执行结束后,可能仍然执行后续逻辑,存在内存泄漏等安全风险 doSomethingAfter(result) } asyncWrapper() }, [state]) // 推荐 useAsyncEffect(async (isCancelled) => { const result = await doSomethingAsync() if(isCancelled()) { // 如果当前 Effect 执行结束,不会执行后续逻辑 clearSomething() return } doSomethingAfter(result) }, [state]) 常见场景 防抖和节流 推荐使用 useDebouncedFn 和 useThrottledFn 两个 Hook 来处理常见的防抖和节流功能,当然也有 useDebouncedEffect 和 useDebouncedEffect 两个 Hook ,用于处理防抖和节流的副作用,但一般情况下,我们更推荐前者。 详情参考 useDebouncedFn 和 useThrottledFn。 const handleSubmit = (value) => console.log(value) const debouncedHandleSubmit = useDebouncedFn(handleSubmit, 500) const handleScroll = (event) => console.log('scroll') const throttledHandleScroll = useThrottledFn(handleScroll, 500) 处理事件 useEventListener 用于在组件挂载时添加事件监听器,组件卸载时自动移除事件监听器,适用于需要添加事件监听器的场景。任何实现了 EventTarget 接口的对象都可以作为第一个参数传入,例如 window、document、ref.current 等。 // 符合以下接口的对象都可以作为第一个参数传入,SSR 下支持 `() => window` 的写法 export interface InferEventTarget<Events> { addEventListener: (event: Events, fn?: any, options?: any) => any removeEventListener: (event: Events, fn?: any, options?: any) => any } 详情参考 useEventListener。 // 不推荐 useEffect(() => { const handler = () => doSomething() window.addEventListener('resize', handler, { passive: true }) return () => { window.removeEventListener('resize', handler) } }, []) // 推荐,且 SSR 友好 useEventListener('resize', doSomething, { passive: true }) // useEventListener(() => window, 'resize', doSomething, { passive: true }) 复制到剪贴板 useClipboard 用于复制文本到剪贴板,适用于需要复制文本到剪贴板的场景,默认情况下使用 Clipboard API ,如果浏览器不支持,则自动优雅降级到 document.execCommand('copy')。 详情参考 useClipboard。 // 不推荐 const copyToClipboard = () => { const input = document.createElement('input') document.body.appendChild(input) input.value = 'Hello, React' input.select() document.execCommand('copy') document.body.removeChild(input) } // 不推荐,引入了额外依赖,使用体验割裂 import copy from 'copy-to-clipboard' import CopyToClipboard from 'react-copy-to-clipboard' // 推荐 const clipboard = useClipboard() clipboard.copy('Hello, React') 时间格式化 useDateFormat 用于格式化时间,轻量、灵活、使用体验统一,适用于需要格式化时间的场景,支持自定义格式化字符串。 详情参考 useDateFormat。 // 不推荐,引入了额外依赖,使用体验割裂 import dayjs from 'dayjs' // 使用约定式格式化 tokens dayjs('2024/09/01').format('YYYY-MM-DD HH:mm:ss') // 不推荐,引入了额外依赖,使用体验割裂 import moment from 'moment' // 使用约定式格式化 tokens moment('2024/09/01').format('YYYY-MM-DD HH:mm:ss') // 不推荐,引入了额外依赖,使用体验割裂 import dateFns from 'date-fns' // date-fns v2 开始使用 unicode 标准的格式化 tokens dateFns.format(new Date(), 'yyyy-MM-dd HH:mm:ss') // 推荐 // 默认使用约定式的格式化 tokens const time = useDateFormat('2024/09/01', 'YYYY-MM-DD HH:mm:ss') const time = useDateFormat(1724315857591, 'YYYY-MM-DD HH:mm:ss') // 同时支持 Unicode 标准的格式化 tokens const time = useDateFormat(new Date(), 'yyyy-MM-dd HH:mm:ss', { unicodeSymbols: true }) 定时器 日常开发中经常使用 setTimeout 和 setInterval 来处理定时任务,直接使用相对繁琐,且要求开发者手动清理定时器,容易出现忘记清理、清理不及时等问题。 // 不推荐 useEffect(() => { const timer = setTimeout(() => { doSomething() }, 1000) return () => clearTimeout(timer) }, []) @shined/react-use 提供了 useTimeoutFn 和 useIntervalFn 两个 Hook 来处理定时任务,自动清理定时器,避免出现忘记清理、清理不及时等问题。 详情参考 useTimeoutFn 和 useIntervalFn。 // 推荐 useTimeoutFn(doSomething, 1000, { immediate: true }) useIntervalFn(doSomething, 1000, { immediate: true }) 浏览器 API 我们经常需要调用浏览器 API 来实现一些功能,包括但远不限于: 使用 Fullscreen API 进行全屏操作 使用 ResizeObserver API 监听元素尺寸变化 使用 Network Information API 获取网络状态 使用 EyeDropper API 获取屏幕颜色 使用 Geolocation API 获取用户地理位置 使用 Battery Status API 获取设备电量 直接操作 API 可能会让代码变得复杂、难以维护,由于 API 的兼容性问题,开发者在处理这些问题时不仅增加了识别兼容情况的心智负担,还可能需要在识别后,增加代码复杂度以实现兼容(如使用历史遗留的 API 实现尽可能兼容)。此外,还需注意许多细节以适应 React 组件化开发。 例如,Fullscreen API在不同浏览器及其版本中的实现有所不同,Battery Status API只在部分浏览器中得到支持,而EyeDropper API目前仅在最新的 Chrome 和 Edge 浏览器中可用。 幸运的是,@shined/react-use 已经封装了许多常用的浏览器 API 以提供更好的使用体验,同时许多浏览器 API 相关的 Hooks 内部使用了 useSupported 统一返回了 API 的支持情况,使得开发者可以更加方便地使用浏览器 API 。 想了解更多可用的浏览器 API Hooks ,请访问 Hooks 列表页 的 Browser 分类。 SSR 相关 @shined/react-use 旨在提供更好的服务端渲染支持,所有 Hooks 都兼容服务端渲染,且不会产生副作用。 useIsomorphicLayoutEffect useIsomorphicLayoutEffect 用于在服务端渲染时使用 useLayoutEffect,在客户端渲染时使用 useEffect,适用于需要在服务端渲染时执行同步副作用的场景。 详情参考 useIsomorphicLayoutEffect。 // 不推荐,SSR 时会抛出警告 useLayoutEffect(() => { doSomething() }, [state]) // 推荐,在运行时自动决定使用 `useLayoutEffect` 或 `useEffect` useIsomorphicLayoutEffect(() => { doSomething() }, [state]) useCallback 与 useMemo useCallback 和 useMemo 是 React 中用于性能优化的 Hook ,常用来缓存函数和值,避免不必要的重复计算。 但是在实际开发中,我们除了性能优化外,可能还需要确保引用稳定性,以避免不必要的副作用等问题。而根据官方文档,useCallback 和 useMemo 仅供用于性能优化,并不保证引用稳定,因此在某些场景下可能会导致不稳定的行为。 如果你需要优化性能的同时还想确保函数、结果的稳定,那么你可以尝试 useStableFn 与 useCreation。 useStableFn useStableFn 用于确保函数引用稳定,适用于需要确保函数引用稳定的场景,例如传递给子组件的回调函数。 详情参考 useStableFn。 // 不推荐 const handleClick = () => { console.log('click') } return <HeavyComponent onClick={handleClick} /> // 推荐 const handleClick = useStableFn(() => { console.log('click') }) return <HeavyComponent onClick={handleClick} /> useCreation useCreation 用于初始化操作,适用于需要确保初始化操作只执行一次的场景,例如初始化复杂对象、耗时操作等,useCreation 除了性能优化外,还能确保结果在不同渲染周期间保持引用稳定。 详情参考 useCreation。 // 不推荐 const heavyResult = useMemo(() => doHeavyWorkToInit(), []) const dynamicResult = useMemo(() => doHeavyWorkToCreate(), [dependency]) // 推荐 const heavyResult = useCreation(() => doHeavyWorkToInit()) const dynamicResult = useCreation(() => doHeavyWorkToCreate(), [dependency]) 进阶指引 如果你需要封装自定义 Hook ,或者需要更多高级功能,可以参考以下进阶指引。 useStableFn 参考上文。 useLatest 参考上文。 useTargetElement useTargetElement 用于获取目标元素,适用于需要获取目标元素的场景,例如在自定义 Hook 中获取目标元素,确保使用体验的一致性。 详情参考 useTargetElement 和 ElementTarget。 const ref = useRef<HTMLDivElement>(null) // <div ref={ref} /> const targetRef = useTargetElement(ref) const targetRef = useTargetElement('#my-div') const targetRef = useTargetElement('#my-div .container') const targetRef = useTargetElement(() => window) const targetRef = useTargetElement(() => document.getElementById('my-div')) // 不推荐,会引起 SSR 问题 const targetRef = useTargetElement(window) // 不推荐,会引起 SSR 问题 const targetRef = useTargetElement(document.getElementById('my-div')) useCreation useCreation 用于初始化操作,适用于需要确保初始化操作只执行一次的场景,例如初始化复杂对象、耗时操作等,useCreation 除了性能优化外,还能确保结果在不同渲染周期间保持引用稳定。 详情参考 useCreation。 const initResult = useCreation(() => doHeavyWorkToInit()) useSupported useSupported 用于获取浏览器 API 的支持情况,适用于需要判断浏览器 API 支持情况的场景。 详情参考 useSupported。 const supported = useSupported('BatteryStatus') usePausable usePausable 用于创建一个 Pausable 实例,以赋予 Hooks 可暂停的能力,适用于需要暂停和恢复的场景。 详情参考 usePausable。 const pausable = usePausable(false, pauseCallback, resumeCallback) useGetterRef useGetterRef 暴露了一个函数以获取 ref.current 的最新值,适用于需要存储状态但不想触发重新渲染,同时需要获取最新值的场景。 详情参考 useGetterRef。 const [isActive, isActiveRef] = useGetterRef(false) 写在最后 useEffect 和 useState 确实是构建 React 应用的基础。然而,掌握更高级、安全、稳定的 Hooks 和相关技术,能让我们创建更为优雅和高效的应用、提高代码可读性、减少 bug 、提高开发幸福感。 优秀的代码不仅仅是完成需求,更在于它的可读性、可维护性和扩展性。投资时间去学习新的工具和技术,不断重构和优化现有代码,是提升代码质量不可或缺的一环。鼓励将本指南作为起点,深入研究每一个概念,并在实践中不断尝试和反思。 无论你是 React 新手还是有经验的开发者,希望通过本指南的学习和应用,你能够把 React 应用的质量提升到一个新的水平。记得,编程是一个不断学习和成长的过程,保持好奇心,不断挑战自己,你一定能够在这条道路上越走越远。 祝 React 旅途愉快。
-
发现自己情况有点类似,本来想回复的,索性直接开一帖,把一些话发出来也给自己解解压。 我今年也 28 了,之前在一家医疗行业做前端开发,其实还是挺不错的,后面因为各种原因(这里说一下一个是工资一直没涨,我在公司负责的内容越来越多。另一个是当时买的基金亏钱了亏了 20%左右大概 2w 多,直接影响了每天的心情)长时间下来我觉得我也抑郁了,反正就是每天一到公司内心就开始难受,就想离职。在 23 年年初过完年我直接裸辞了,当时我也知道行情不好,还是毅然选择裸辞。当时跟领导提出要辞职后心里一下就好受多了,感觉一块大石头落地那种感觉。 后面开始找工作,找了两个月没找到有点焦虑了,终于在 5 月份拿到了一份工作,薪资也有涨,技术栈从 vue 转到 react ,我觉得能胜任然后当时也不是很想继续再找了,就入职了。事实做下来技术这块也确实没问题,react 上手的很快。不过有个问题是做的事比较多,不是指开发,公司没有产品没有 ui ,原型图要前端去画,功能设计还要我自己去想,只有一个大纲。所以有点受不了,再加上买的基金没有及早抽身出来又亏了不少,还有下半年的时候我妈身体不好,去医院也花了不少钱做了不少次检查,最后也没查出具体问题(腹部痛腿痛这些,肠镜胃镜都做了也没查出问题),最后在新冠病毒变异时我中招了,身体上很难受再加上心里上的长期压抑,导致我又一次冲动离职。回到公司第二天我就跟领导提了。 之后本来打算尽快找到工作的,然后找了两个月没什么回复,就索性懒得找了,准备躺平。 人一闲下来就容易胡思乱想,就觉得看不到希望,在大城市房子也买不起,女朋友也没有。没人可以倾诉,不跟父母倾诉也是不想让他们担心。有时候真的就觉得活得好没意思,好痛苦。 8 月初我注销了基金账户,简单收拾了下行李来合肥找工作(离家近,芜湖),投了两个星期吧,拿了 3 个 offer ,拒掉其中一个,选择了一家小公司,部门是初创的 2 前端 2 后端。入职一周的时候 hr 交社保的时候被告知社保是代缴的(什么人力资源公司),因为公司注册地不在合肥,这个是之前沟通时没跟提过,唉不过我自己也没问。然后我正好打算申请合肥的住房补贴(一个月 1250 ),结果这样我就不能申请了。于是我找了之前的一个 offer ,讯飞外包,准备去干着看看。这里也是非常冲动,没怎么考虑。 去了外包后发现内网开发真受不了,办公电脑配置也差的要死 8g 内存。 我当天就不干了,然后我又想回原来那家,但被 hr 告知离职公司规定离职后不得再入职了,其实我也是厚着脸皮了,正常人肯定不会再去找原单位了 也是自从第一次离职后,感觉我越来越容易冲动离职了。第一次离职我犹豫了半年。 现在的情况是合肥这边岗位少的可怜,能投的基本都被投过了。 唉大好的机会给我却被我浪费了。 后续也不知道怎么办了,有想过要么回上海继续找。 说出来后感觉轻松了一点,今天一天心情真的超压抑
-
我买了彩云天气好多年的会员,但是界面广告越来越多,越来越丑,loading 时间过长,小组件更新不及时,推送广告,反正一堆的问题,不打算忍了。 所以想换一个体验更好的天气 App ,Android 的,可以接受付费,用的类原生 Android 系统自带的天气不好用,大家有什么推荐的吗?
-
刚准备去洗澡,看了一下手机发现支付宝提示收款 19.9 元。 我没想到我居然迎来了我的第一位 vip 充值!说实话当时有点激动,现在冷静下来写一个博客记录了一下。 https://blog.axiaoxin.com/post/milestone-first-vip/ 嘿嘿。开心的事分享给大家。
-
编程小白,在写一个多线程目录文件遍历的时候,出现了阻塞问题,求教各位大佬~ 通过增大 var taskChan = make(chan string, 1000),chan 缓冲区为 100 万的时候程序不会阻塞 但是我通过打印日志发现 taskChan 占用很小,只有十几,而且存在通道写入失败的情况 taskChan 的缓冲区为 1000 时,阻塞的日志如下: [DEBUG]:增加目录,增加 wg, [1802], taskChan = [0] [ERROR]:写入通道失败... [DEBUG]:增加目录,增加 wg, [1842], taskChan = [0] [ERROR]:写入通道失败... [DEBUG]:增加目录,增加 wg, [1843], taskChan = [0] [ERROR]:写入通道失败... [DEBUG]:增加目录,增加 wg, [1844], taskChan = [0] [DEBUG]:增加目录,增加 wg, [1801], taskChan = [5] [DEBUG]:任务完成,减小 wg, [1798], taskChan = [1] [DEBUG]:任务完成,减小 wg, [1797], taskChan = [17] [DEBUG]:任务完成,减小 wg, [1816], taskChan = [4] [DEBUG]:增加目录,增加 wg, [1803], taskChan = [1] [DEBUG]:任务完成,减小 wg, [1843], taskChan = [1] [DEBUG]:任务完成,减小 wg, [1797], taskChan = [21] [DEBUG]:任务完成,减小 wg, [1841], taskChan = [24] [DEBUG]:增加目录,增加 wg, [1841], taskChan = [0] [DEBUG]:增加目录,增加 wg, [1841], taskChan = [0] [DEBUG]:增加目录,增加 wg, [1841], taskChan = [0] [DEBUG]:增加目录,增加 wg, [1841], taskChan = [0] [DEBUG]:任务完成,减小 wg, [1840], taskChan = [6] [DEBUG]:任务完成,减小 wg, [1798], taskChan = [0] [DEBUG]:任务完成,减小 wg, [1840], taskChan = [13] [ERROR]:写入通道失败... [DEBUG]:增加目录,增加 wg, [1840], taskChan = [0] [DEBUG]:增加目录,增加 wg, [1841], taskChan = [0] [DEBUG]:增加目录,增加 wg, [1842], taskChan = [0] [DEBUG]:增加目录,增加 wg, [1842], taskChan = [2] [DEBUG]:增加目录,增加 wg, [1842], taskChan = [0] [DEBUG]:增加目录,增加 wg, [1843], taskChan = [0] [ERROR]:写入通道失败... [DEBUG]:增加目录,增加 wg, [1844], taskChan = [0] [ERROR]:写入通道失败... [DEBUG]:增加目录,增加 wg, [1845], taskChan = [0] [ERROR]:写入通道失败... [DEBUG]:增加目录,增加 wg, [1846], taskChan = [0] [ERROR]:写入通道失败... [DEBUG]:增加目录,增加 wg, [1847], taskChan = [0] [ERROR]:写入通道失败... [DEBUG]:增加目录,增加 wg, [1848], taskChan = [0] [ERROR]:写入通道失败... [DEBUG]:增加目录,增加 wg, [1849], taskChan = [0] 如果把 taskChan 的缓冲区为 100 万的时候,程序可以正常退出,日志如下: [DEBUG]:增加目录,增加 wg, [2], taskChan = [0] [DEBUG]:增加目录,增加 wg, [3], taskChan = [0] [DEBUG]:增加目录,增加 wg, [4], taskChan = [0] [DEBUG]:任务完成,减小 wg, [3], taskChan = [0] [DEBUG]:任务完成,减小 wg, [3], taskChan = [0] [DEBUG]:任务完成,减小 wg, [3], taskChan = [0] [DEBUG]:任务完成,减小 wg, [1], taskChan = [0] [DEBUG]:增加目录,增加 wg, [4], taskChan = [0] [DEBUG]:增加目录,增加 wg, [2], taskChan = [0] [DEBUG]:任务完成,减小 wg, [1], taskChan = [0] [DEBUG]:任务完成,减小 wg, [2], taskChan = [0] [DEBUG]:任务完成,减小 wg, [2], taskChan = [0] [DEBUG]:任务完成,减小 wg, [1], taskChan = [0] [DEBUG]:任务完成,减小 wg, [1], taskChan = [0] [DEBUG]:任务完成,减小 wg, [0], taskChan = [0] [INFO]:目录扫描完毕 [DEBUG]:func GetAllFilePath end [DEBUG]:func StartScan end [DEBUG]:func btnStartScanOnclick end 代码如下: package core import ( "DopliGo/logs" "github.com/panjf2000/ants/v2" "os" "path/filepath" "sync" "sync/atomic" ) func GetAllFilePath(rootPath string) { //logs.IsLogDebug = false logs.Debug("func GetAllFilePath start") // 创建任务通道和结果通道 var taskChan = make(chan string, 1000000) var resultChan = make(chan string, 1000000) var wg sync.WaitGroup var counter int64 = 0 // 创建生产者 goroutine 池 producerPool, _ := ants.NewPoolWithFunc(16, func(i interface{}) { produceTasks(i.(string), taskChan, resultChan, &counter, &wg) }) logs.Debug("cap:%d", producerPool.Cap()) defer producerPool.Release() taskChan <- rootPath wg.Add(1) // 这里增加计数器 atomic.AddInt64(&counter, 1) logs.Debug("任务开始,增加 wg, [%d], taskChan = [%d]", atomic.LoadInt64(&counter), len(resultChan)) // 启动生产者 go func() { //defer logs.Debug("生产者退出") for task := range taskChan { err := producerPool.Invoke(task) if err != nil { logs.Error("failed to producerPool Invoke, err: %s", err) return } } }() // 启动结果处理 goroutine go func() { //defer logs.Debug("消费者退出") for result := range resultChan { _ = result } }() // 等待所有任务完成 wg.Wait() close(resultChan) close(taskChan) logs.Info("目录扫描完毕") logs.Debug("func GetAllFilePath end") } func produceTasks(rootPath string, taskChan chan string, resultChan chan string, counter *int64, wg *sync.WaitGroup) { defer wg.Done() // 确保每次 produceTasks 完成时,调用 Done // logs.Debug("func produceTasks start") entries, err := os.ReadDir(rootPath) if err != nil { logs.Error("failed to read dir: %s , err: %s", rootPath, err) return } for _, entry := range entries { path := filepath.Join(rootPath, entry.Name()) if entry.IsDir() { wg.Add(1) atomic.AddInt64(counter, 1) select { case taskChan <- path: // 发送成功 default: // 发送失败,通道已满 logs.Error("写入通道失败...") } logs.Debug("增加目录,增加 wg, [%d], taskChan = [%d]", atomic.LoadInt64(counter), len(resultChan)) } else { resultChan <- path } } atomic.AddInt64(counter, -1) logs.Debug("任务完成,减小 wg, [%d], taskChan = [%d]", atomic.LoadInt64(counter), len(resultChan)) //logs.Debug("func produceTasks end") }
-
有一个 tcp 服务,连接成千上万的设备 有一个 websocket 服务,连接用户端 如 web ,小程序,app 等 用户发送的请求通过 websocket 通知给 tcp 到设备,下面 2 种方案怎么选择? tcp 和 websocket 服务合并成单个服务开发部署 缺点:每次重启 ws 就要重启 tcp , 优点:不需要 2 个服务之间通信 tcp 和 ws 分开部署 缺点: 服务间需要通信,要么 ws 开一个 tcp 客户端,要么用消息中间件, 增加维护成本 优点:ws 可以单独重启,ws 服务上含有业务 api
-
最近刚刚折腾了一把,分享下我买美区 AC+的过程,也想问问有没有人在中国大陆/香港使用过美区 AC+的?使用的体验是什么样的? 因为 Apple Intelligence 锁中国大陆的硬件,于是把原来的国行 AC+的 iPad Pro M1 卖掉了,找人从澳门伦敦人的 Apple Store 带回来了一台 M4 的 iPad Pro ,有小票。 结果因为不熟悉情况,收到才发现澳门和香港的 iPad 还是有区别的,具体在于澳门的不能在 iPad 设置里面买 AC+,只能线下购买或者电话购买。 先是尝试去拨打澳门的 Apple Support 电话,结果无法接通,退而求其次拨打澳门伦敦人店的电话,结果那时候他们还没开业,不在营业时间 w 不接电话。 最终拨打了香港的 Apple Support 电话,接通之后发现只有广东话和英语,就选择了英语客服。之后的过程倒是挺顺利的,只是由于没有显示 this device is eligible for AppleCare+,客服让我额外运行并且上传了个设备诊断日志作为补充。客服还说按月订阅的方案无法选择,只能先买两年的。 购买的 AppleCare+是与当前登录的 Apple ID 绑定的,我登录的是美区,所以收到的邮件就是美区 AC+的链接,点进去之后支付只支持美国发行的卡,无论是输入 cvv 还是直接 Apple Pay ,还好我有张美卡,支付顺利。这里还有个题外话题外话,当时我问客服港卡是否可以支付,她告诉我可以,结果最终验证结果是不行的。 买完之后很快就收到了邮件,AppleCare+ Proof of Coverage ,另外买完之后如果你还有 Apple Pencil Pro 或者 Magic Keyboard 的话,需要把序列号也报给客服,她再做一次绑定。 这次算是踩了一个坑,按理说我这种直营店买的有收据的也不会被刁难使用 AC+,不知道有没有人真的在中国大陆或者香港用过美区 AC+,是什么体验?
-
从网上的信息看,发达国家普遍松弛,收入也不错,有相当的时间去消费以及做自己喜欢的事。有经历的老哥来聊聊,事实真的是这样吗?
-
食谱的内容大多来自一些自己的尝试、或是《食帖》杂志,或是 B 站一些 up 主。记录的食谱都已经是自己已经烹饪过的。 大部分的食谱内容都适合 1 人食或者 2 人食。 链接: https://food.sayidhe.com/ 后续想打造一个基于节气、地理位置等的食谱日历,有烹饪兴趣的也可以一起来玩。
-
Macbook 12 寸是我认为最经典的机型之一。但是这个机子主板设计有缺陷,没有散热。导致散热不好,经常丢硬盘。海鲜市场很多机子。A1534 型号。 然后闲着无聊收了很多尸体机子个人捣鼓。因为不是修电脑的。就拿起来组合着玩。 我搞了个外置固态硬盘启动,然后搞了 opencore legacy ,上了 sonoma 。 然后就拿来当副屏幕使用,可以直接从主屏幕移动到副屏幕使用。可以做一些工作的跟踪,听音乐,看视频。 当然还能熟悉 sonoma 系统。都是插电使用。 当然也搞了很多配件出来,键盘,螺丝,触控板,现在很熟悉 macbook 内部构造了。 简直是什么都学到了。 唉。哎。有同好的么?
-
岗位:Golang/K8s/开发/运维/架构等 地点:北京 联系方式:微信同昵称 ● 简述 有 10 多年的工作经验,有云计算领域的相关技术发明专利 6 项,在架构设计,分布式系统,和优化上有一定积累;能带团队,能做架构,也能独立攻克一些 技术难题;是开源社区的积极代码贡献者(github.com/jmzwcn),如 Docker ,gRPC 等,获得 CNCF 认证的 Kubernetes 云原生资格 CKA 证书(证 号:LF-kw0dx02itf)。 ● 工作经验 2023/01–2024/01:爱康国宾健康体检集团 裁员;集团技术部架构师,参与公司范围内的技术架构,技术方案,技术评 审,新技术推广等工作;推动云原生 K8s 平台的落地,指导公司各个业务系统 的一些上云 POC ,上云实施等流程;解决公司一些长期积累的问题,如流量 LB 的版本化/可视化能力。 2021/04--2022/12:百度网络技术有限公司 资深软件工程师,负责百度智能云 ACG 部门下的 ToB 交付平台,(天牛)的开 发与建设工作,该平台为典型微服务架构,个人主要承担平台的交付底座功 能,一个基于 Kubernetes 的部署引擎(DKE)的设计与开发;和 CI/CD 流水线 与多 CPU 架构/多操作系统/多 GPU 卡/多 K8s 版本的适配发版自动化;及场外客 户 onsite 支持等工作。 2017/02--2021/04:新浪网技术(中国)有限公司 作为架构师及主要开发人员,负责搭建新浪网技术部的容器云计算平台,包括 技术选型,方案论证,系统开发等,从无到有,已让新浪网 80%的 WEB 业务 运行于容器云平台之上;主要技术方向是基于 kubernetes 的落地与二次开发, 包括定制化的 CRD ,自定义的策略调度,自动化方向的 cloud-provider 等, 及基础的网络组件 calico ,监控普罗米修斯,存储组件 ceph ,日志组件 fluentd 等 2011/03—2017/01:甲骨文软件(北京)有限公司 1.作为高级软件工程师服务于 Oracle WebLogic 团队,主要负责 Connector/ Spring/Batch 等组件,包括新 feature 和 bug 处理,及相应的功能开发,代码 测试,解决产品 cloud/scrum 化过程中出现的各式问题 2.Weblogic 的 cloud 化相关工作,基于 docker 改造已有 infra 系统,采用 Golang+GRPC+Protobuffer 和微服务模式,使开发测试 CI/CD 流程更高效 的运行。 ●教育经历 2005/09--2008/07 湖北工业大学 计算机科学与技术 硕士研究生 2000/09--2004/07 三峡大学 数学与应用数学 本科 ----------- 从 12 月底裁员开始,起初还有几个面试,可能期望值太高吧,大公司的架构师/专家岗级别,面完也没下文,现在是越来越凉,面试机会都没了。43 岁,家庭压力大,不知道哪位兄弟公司有机会,帮忙推荐一把,感激不尽。