跳转到内容
彼岸论坛

小天管理

管理员
  • 内容数

    16269
  • 注册日期

  • 最后上线

  • 得奖次数

    1

小天管理 发表的所有内容

  1. 按照 40W 来讲,先息后本,每年少了 15.6K ;
  2. 关于我们 - Infinity Ground 正在构建由 AI 技术驱动的下一代游戏平台。采用领先技术,实现了游戏创作的民主化,使得无论技术背景如何,每个人都能轻松打造专属的 AI 游戏体验。我们不仅提供工具,更通过设置独特的激励机制,激发创造力和奖励参与贡献,建立一个富有全新活力的游戏社区。 - 我们的团队聚集了来自剑桥大学、哥伦比亚大学、清华大学等全球化顶尖高校的复合型人才,曾在 Google 、Tiktok 等科技大厂及 AI start-ups 有丰富的实践经验。 - 借助我们独特的技术和深度的行业理解,Infinity Ground 已成为推动游戏创作和玩家体验革新的重要力量。我们坚信,通过助力每一个创者与玩家实现他们的游戏梦想。 岗位 JD:网页 UI/UX 设计师(兼职) 岗位职责: 1 、根据产品需求,设计高质量的网页 UI 界面,确保视觉效果与品牌和产品风格一致。 2 、参与用户体验设计,优化现有界面,提高用户满意度。 3 、与产品经理和开发团队紧密合作,确保设计方案可行且符合项目需求。 4 、根据用户反馈进行迭代设计,持续优化产品体验。 岗位要求: 1 、3 年以上网页 UI/UX 设计经验,具有 Web3 或 AI 行业相关经验者优先。 2 、能够熟练使用设计工具 Figma 等,能够高效地进行设计与原型制作。 3 、具有扎实的视觉设计能力,能够独立完成从概念到最终设计的全过程。 4 、良好的沟通和团队协作能力,能够清晰地传达设计思路并与跨部门团队合作。 5 、具备创意和创新精神,能够根据项目需求提出独特的设计方案。 投递要求: 请在投递简历时以链接/PDF 的形式提交您过往的作品集。 投递简历: hello@infinityg.ai ,备注:姓名+岗位+v2ex
  3. 原本约好一起出来看柯南大电影的 结果突然莫名其妙被拉黑了 隐藏了所有加好友的方式 现在只有个分享名片出去 发送了申请但之后就把名片添加的方式也设置了不能添加 之前有个强制加好友的代码 但实验后貌似对方是收不到好友申请的 求求 v2 大神了 明天就要看电影了
  4. 欢迎全栈开发者加入本群! 这里是各路编程高手的技术交流平台,涵盖了多种主流编程语言和技术栈。 无论你专注于前端(如 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
  5. 看网上直通核显给 win 似乎有点麻烦呢?那其他硬件呢?还能像物理机跑 win 那么丝滑吗? 最近手贱想折腾折腾 ,请大佬赐教! 233
  6. 4070 显卡 想换个 4k 27 寸显示器,有什么型号推荐 感谢各位
  7. 最近一个项目要用到大文件的断点续传,多大文件呢,大的包可能会有 20G ,目前的做法是 前端取到文件后,按 2m 一个片段进行分片,然后逐个上传 后端收到完整的文件后放在一个隐藏的目录内,等最后的文件传完之后,逐一合并,并移动到指定的文件夹 实现是实现了,最大的问题不是上传,而是合并以及转移文件相当消耗时间 有没有更高级的做法呢?
  8. 之前上线了款 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
  9. mac 有什么好用的软件吗(开源的),新装了系统
  10. 在 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 旅途愉快。
  11. 发现自己情况有点类似,本来想回复的,索性直接开一帖,把一些话发出来也给自己解解压。 我今年也 28 了,之前在一家医疗行业做前端开发,其实还是挺不错的,后面因为各种原因(这里说一下一个是工资一直没涨,我在公司负责的内容越来越多。另一个是当时买的基金亏钱了亏了 20%左右大概 2w 多,直接影响了每天的心情)长时间下来我觉得我也抑郁了,反正就是每天一到公司内心就开始难受,就想离职。在 23 年年初过完年我直接裸辞了,当时我也知道行情不好,还是毅然选择裸辞。当时跟领导提出要辞职后心里一下就好受多了,感觉一块大石头落地那种感觉。 后面开始找工作,找了两个月没找到有点焦虑了,终于在 5 月份拿到了一份工作,薪资也有涨,技术栈从 vue 转到 react ,我觉得能胜任然后当时也不是很想继续再找了,就入职了。事实做下来技术这块也确实没问题,react 上手的很快。不过有个问题是做的事比较多,不是指开发,公司没有产品没有 ui ,原型图要前端去画,功能设计还要我自己去想,只有一个大纲。所以有点受不了,再加上买的基金没有及早抽身出来又亏了不少,还有下半年的时候我妈身体不好,去医院也花了不少钱做了不少次检查,最后也没查出具体问题(腹部痛腿痛这些,肠镜胃镜都做了也没查出问题),最后在新冠病毒变异时我中招了,身体上很难受再加上心里上的长期压抑,导致我又一次冲动离职。回到公司第二天我就跟领导提了。 之后本来打算尽快找到工作的,然后找了两个月没什么回复,就索性懒得找了,准备躺平。 人一闲下来就容易胡思乱想,就觉得看不到希望,在大城市房子也买不起,女朋友也没有。没人可以倾诉,不跟父母倾诉也是不想让他们担心。有时候真的就觉得活得好没意思,好痛苦。 8 月初我注销了基金账户,简单收拾了下行李来合肥找工作(离家近,芜湖),投了两个星期吧,拿了 3 个 offer ,拒掉其中一个,选择了一家小公司,部门是初创的 2 前端 2 后端。入职一周的时候 hr 交社保的时候被告知社保是代缴的(什么人力资源公司),因为公司注册地不在合肥,这个是之前沟通时没跟提过,唉不过我自己也没问。然后我正好打算申请合肥的住房补贴(一个月 1250 ),结果这样我就不能申请了。于是我找了之前的一个 offer ,讯飞外包,准备去干着看看。这里也是非常冲动,没怎么考虑。 去了外包后发现内网开发真受不了,办公电脑配置也差的要死 8g 内存。 我当天就不干了,然后我又想回原来那家,但被 hr 告知离职公司规定离职后不得再入职了,其实我也是厚着脸皮了,正常人肯定不会再去找原单位了 也是自从第一次离职后,感觉我越来越容易冲动离职了。第一次离职我犹豫了半年。 现在的情况是合肥这边岗位少的可怜,能投的基本都被投过了。 唉大好的机会给我却被我浪费了。 后续也不知道怎么办了,有想过要么回上海继续找。 说出来后感觉轻松了一点,今天一天心情真的超压抑
  12. 我买了彩云天气好多年的会员,但是界面广告越来越多,越来越丑,loading 时间过长,小组件更新不及时,推送广告,反正一堆的问题,不打算忍了。 所以想换一个体验更好的天气 App ,Android 的,可以接受付费,用的类原生 Android 系统自带的天气不好用,大家有什么推荐的吗?
  13. AI Demon Name Generator。
  14. 刚准备去洗澡,看了一下手机发现支付宝提示收款 19.9 元。 我没想到我居然迎来了我的第一位 vip 充值!说实话当时有点激动,现在冷静下来写一个博客记录了一下。 https://blog.axiaoxin.com/post/milestone-first-vip/ 嘿嘿。开心的事分享给大家。
  15. 编程小白,在写一个多线程目录文件遍历的时候,出现了阻塞问题,求教各位大佬~ 通过增大 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") }
  16. 有一个 tcp 服务,连接成千上万的设备 有一个 websocket 服务,连接用户端 如 web ,小程序,app 等 用户发送的请求通过 websocket 通知给 tcp 到设备,下面 2 种方案怎么选择? tcp 和 websocket 服务合并成单个服务开发部署 缺点:每次重启 ws 就要重启 tcp , 优点:不需要 2 个服务之间通信 tcp 和 ws 分开部署 缺点: 服务间需要通信,要么 ws 开一个 tcp 客户端,要么用消息中间件, 增加维护成本 优点:ws 可以单独重启,ws 服务上含有业务 api
  17. 最近刚刚折腾了一把,分享下我买美区 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+,是什么体验?
  18. 最高温普遍 43°C https://imgur.com/FZAEu9s.jpg
  19. 从网上的信息看,发达国家普遍松弛,收入也不错,有相当的时间去消费以及做自己喜欢的事。有经历的老哥来聊聊,事实真的是这样吗?
  20. DOGS 可以充值到 OKX 了,但是一天过去了还没到账,有遇到过这个问题的吗
  21. 食谱的内容大多来自一些自己的尝试、或是《食帖》杂志,或是 B 站一些 up 主。记录的食谱都已经是自己已经烹饪过的。 大部分的食谱内容都适合 1 人食或者 2 人食。 链接: https://food.sayidhe.com/ 后续想打造一个基于节气、地理位置等的食谱日历,有烹饪兴趣的也可以一起来玩。
×
×
  • 创建新的...