<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Bubblog</title>
	<atom:link href="https://blog.yangyuanping.com/feed/" rel="self" type="application/rss+xml" />
	<link>https://blog.yangyuanping.com</link>
	<description>nullable reference types</description>
	<lastBuildDate>Tue, 17 Feb 2026 15:16:11 +0000</lastBuildDate>
	<language>zh-Hans</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.1</generator>

<image>
	<url>https://blog.yangyuanping.com/wp-content/uploads/2025/11/cropped-patrick_log_logo_251121-2-32x32.png</url>
	<title>Bubblog</title>
	<link>https://blog.yangyuanping.com</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>CSS Grid 与 Flexbox 深度对比：何时使用哪个布局方案？</title>
		<link>https://blog.yangyuanping.com/css-grid-%e4%b8%8e-flexbox-%e6%b7%b1%e5%ba%a6%e5%af%b9%e6%af%94%ef%bc%9a%e4%bd%95%e6%97%b6%e4%bd%bf%e7%94%a8%e5%93%aa%e4%b8%aa%e5%b8%83%e5%b1%80%e6%96%b9%e6%a1%88%ef%bc%9f/</link>
		
		<dc:creator><![CDATA[peny911]]></dc:creator>
		<pubDate>Tue, 17 Feb 2026 15:16:11 +0000</pubDate>
				<category><![CDATA[未分类]]></category>
		<guid isPermaLink="false">https://blog.yangyuanping.com/?p=1124</guid>

					<description><![CDATA[在现代前端开发中，CSS Grid 和 Flexbox 是两个最强大的布局工具。很多开发者知道它们的基本用法， [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>在现代前端开发中，CSS Grid 和 Flexbox 是两个最强大的布局工具。很多开发者知道它们的基本用法，但在实际项目中常常纠结：这个场景该用 Grid 还是 Flexbox？本文将通过实战案例深入解析两者的适用场景和组合使用技巧。</p>
<h2>核心区别：一维 vs 二维</h2>
<p>最本质的区别在于：</p>
<ul>
<li><strong>Flexbox</strong>：一维布局系统，适合处理<strong>行或列</strong>方向的排列</li>
<li><strong>Grid</strong>：二维布局系统，同时控制<strong>行和列</strong>的精确定位</li>
</ul>
<p>这不是说 Flexbox 不能做二维布局，而是 Grid 在二维场景下更加优雅和高效。</p>
<h2>实战案例 1：导航栏布局</h2>
<p>导航栏是典型的<strong>一维布局</strong>场景，Flexbox 是最佳选择：</p>
<pre><code>.navbar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 1rem 2rem;
}

.nav-links {
  display: flex;
  gap: 2rem;
  list-style: none;
}

.nav-links li {
  white-space: nowrap;
}

/* 响应式：小屏幕垂直排列 */
@media (max-width: 768px) {
  .navbar {
    flex-direction: column;
    gap: 1rem;
  }
}</code></pre>
<p><strong>为什么用 Flexbox？</strong></p>
<ul>
<li>导航项按<strong>单一方向</strong>排列</li>
<li><code>gap</code> 属性自动处理间距</li>
<li><code>flex-direction</code> 轻松切换横竖布局</li>
</ul>
<h2>实战案例 2：卡片网格布局</h2>
<p>产品列表、图片墙等<strong>网格场景</strong>，Grid 完胜：</p>
<pre><code>.card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 2rem;
  padding: 2rem;
}

.card {
  background: white;
  border-radius: 8px;
  overflow: hidden;
  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}</code></pre>
<p><strong>Grid 的优势：</strong></p>
<ul>
<li><code>auto-fit + minmax</code> 实现<strong>完美自适应</strong>，无需媒体查询</li>
<li>自动填充空间，每个卡片宽度一致</li>
<li>比 Flexbox 的 <code>flex-wrap</code> 方案更可控</li>
</ul>
<h2>实战案例 3：复杂页面布局</h2>
<p>圣杯布局（Header + Sidebar + Main + Footer）是 Grid 的杀手级应用：</p>
<pre><code>.app-layout {
  display: grid;
  grid-template-areas:
    "header header header"
    "sidebar main aside"
    "footer footer footer";
  grid-template-columns: 250px 1fr 300px;
  grid-template-rows: auto 1fr auto;
  min-height: 100vh;
}

.header  { grid-area: header; }
.sidebar { grid-area: sidebar; }
.main    { grid-area: main; }
.aside   { grid-area: aside; }
.footer  { grid-area: footer; }

/* 响应式：小屏幕单列布局 */
@media (max-width: 1024px) {
  .app-layout {
    grid-template-areas:
      "header"
      "main"
      "aside"
      "footer";
    grid-template-columns: 1fr;
  }
}</code></pre>
<p><strong>Grid 的语义化优势：</strong></p>
<ul>
<li><code>grid-template-areas</code> 让布局结构<strong>一目了然</strong></li>
<li>调整布局只需改变 <code>areas</code> 定义，无需修改 HTML</li>
<li>轻松实现复杂的<strong>跨行跨列</strong>效果</li>
</ul>
<h2>高级技巧：Grid + Flexbox 组合</h2>
<p>真正的高手懂得<strong>组合使用</strong>两者。典型场景：Grid 定义整体框架，Flexbox 处理内部细节。</p>
<pre><code>/* Grid 控制整体布局 */
.dashboard {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1.5rem;
}

/* Flexbox 处理卡片内部对齐 */
.widget {
  display: flex;
  flex-direction: column;
  padding: 1.5rem;
  background: white;
  border-radius: 8px;
}

.widget-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 1rem;
}

.widget-content {
  flex: 1; /* 占据剩余空间 */
}

.widget-footer {
  margin-top: auto; /* 推到底部 */
  padding-top: 1rem;
  border-top: 1px solid #eee;
}</code></pre>
<h2>性能考量</h2>
<p>两者的渲染性能相当，但有细微差异：</p>
<table>
<tr>
<th>场景</th>
<th>推荐方案</th>
<th>原因</th>
</tr>
<tr>
<td>动态添加元素</td>
<td>Flexbox</td>
<td>Grid 需要重新计算整个网格</td>
</tr>
<tr>
<td>固定结构</td>
<td>Grid</td>
<td>浏览器可预先优化布局计算</td>
</tr>
<tr>
<td>大量嵌套</td>
<td>避免过度嵌套</td>
<td>两者都会增加计算成本</td>
</tr>
</table>
<h2>决策树：如何选择？</h2>
<pre><code>需要二维精确定位？
├─ 是 CSS Grid
└─ 否
   |
   需要内容自适应宽度？
   ├─ 是 Flexbox (justify-content)
   └─ 否
      |
      需要复杂的对齐控制？
      ├─ 是 Flexbox (align-items/self)
      └─ 否 看具体需求，两者皆可</code></pre>
<h2>浏览器兼容性</h2>
<ul>
<li><strong>Flexbox</strong>：IE 10+ （需要前缀）</li>
<li><strong>Grid</strong>：IE 11+（部分支持，需要旧语法）、现代浏览器完全支持</li>
<li>生产环境建议使用 <strong>Autoprefixer</strong> 自动处理兼容性</li>
</ul>
<h2>总结</h2>
<p>掌握 Grid 和 Flexbox 的核心原则：</p>
<ul>
<li><strong>Flexbox</strong>：内容驱动布局，适合<strong>组件内部</strong>细节排列</li>
<li><strong>Grid</strong>：结构驱动布局，适合<strong>页面级</strong>框架搭建</li>
<li><strong>组合使用</strong>：Grid 定框架，Flexbox 调细节</li>
</ul>
<p>不要陷入&#8221;只用其一&#8221;的误区，根据场景灵活选择才是专业开发者的标志。实际项目中，80% 的布局问题都可以用这两个工具优雅解决，无需依赖第三方框架。</p>
<p><em>（本文基于 CSS3 最新规范和现代浏览器最佳实践整理，适合有一定 CSS 基础的开发者深入学习）</em></p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>C# 异步编程：从入门到精通的最佳实践</title>
		<link>https://blog.yangyuanping.com/c-%e5%bc%82%e6%ad%a5%e7%bc%96%e7%a8%8b%ef%bc%9a%e4%bb%8e%e5%85%a5%e9%97%a8%e5%88%b0%e7%b2%be%e9%80%9a%e7%9a%84%e6%9c%80%e4%bd%b3%e5%ae%9e%e8%b7%b5/</link>
		
		<dc:creator><![CDATA[peny911]]></dc:creator>
		<pubDate>Sun, 15 Feb 2026 16:38:21 +0000</pubDate>
				<category><![CDATA[未分类]]></category>
		<guid isPermaLink="false">https://blog.yangyuanping.com/?p=1121</guid>

					<description><![CDATA[C# 的 async/await 关键字让异步编程变得前所未有的简单，但这种简洁性有时会隐藏底层的复杂性。本文 [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>C# 的 async/await 关键字让异步编程变得前所未有的简单，但这种简洁性有时会隐藏底层的复杂性。本文将深入探讨异步编程的最佳实践，帮助你写出更高效、更可靠的异步代码。</p>
<h2>async/await 基础回顾</h2>
<p>async 和 await 是语法糖，编译器会将它们转换为状态机。关键点在于：</p>
<ul>
<li><strong>async 方法</strong>：返回 Task 或 Task&lt;T&gt;，调用时不会阻塞线程</li>
<li><strong>await 表达式</strong>：等待任务完成，期间释放线程</li>
<li><strong>ConfigureAwait(false)</strong>：跨线程上下文优化性能</li>
</ul>
<pre><code>// 基础异步方法
public async Task&lt;User&gt; GetUserAsync(int id)
{
    var user = await _userRepository.FindByIdAsync(id);
    return user;
}

// 库代码中的最佳实践
public async Task&lt;IEnumerable&lt;User&gt;&gt; GetAllUsersAsync()
{
    var users = await _userRepository.GetAllAsync()
        .ConfigureAwait(false); // 不需要同步上下文
    return users;
}
</code></pre>
<h2>常见陷阱与解决方案</h2>
<h3>1. 死锁问题</h3>
<pre><code>// &#x274c; 危险：在 UI 线程或 ASP.NET 同步上下文中调用
var user = GetUserAsync(id).Result; // 可能死锁！

// &#x2705; 安全：始终使用 await
var user = await GetUserAsync(id);
</code></pre>
<h3>2. 异常处理</h3>
<pre><code>// &#x274c; 错误：异常被吞掉
try
{
    await Task.Run(() => { throw new Exception("Oops"); });
}
finally
{
    // 这里捕获不到异常
}

// &#x2705; 正确：多个任务并行，统一处理异常
var tasks = new List&lt;Task&gt;
{
    Task1Async(),
    Task2Async(),
    Task3Async()
};

try
{
    await Task.WhenAll(tasks);
}
catch (Exception ex)
{
    // 只能看到第一个异常
    Console.WriteLine($"Exception: {ex.Message}");
}
</code></pre>
<h3>3. void 返回类型</h3>
<pre><code>// &#x274c; 避免：async void 方法
public async void BadMethod()
{
    await Task.Delay(1000);
    // 异常无法被外部捕获！
}

// &#x2705; 推荐：使用 Task 返回类型
public async Task GoodMethod()
{
    await Task.Delay(1000);
    // 异常可以被 await 或 .Result 捕获
}
</code></pre>
<h2>性能优化技巧</h2>
<h3>1. 避免不必要的 async</h3>
<pre><code>// &#x274c; 浪费：不需要 async
public async Task&lt;int&gt; GetValueAsync()
{
    return await ComputeValueAsync(); // 不必要的 await
}

// &#x2705; 高效：直接返回 Task
public Task&lt;int&gt; GetValueAsync()
{
    return ComputeValueAsync();
}
</code></pre>
<h3>2. ValueTask 优化</h3>
<pre><code>// 高频缓存场景：使用 ValueTask 减少内存分配
public async ValueTask&lt;User&gt; GetUserAsync(int id)
{
    // 快速路径：缓存命中，无需分配 Task 对象
    if (_cache.TryGetValue(id, out var user))
        return user;
    
    // 慢速路径：需要异步查询
    user = await _repository.FindByIdAsync(id);
    _cache[id] = user;
    return user;
}
</code></pre>
<h3>3. 并行处理</h3>
<pre><code>// &#x274c; 串行：慢
var user = await GetUserAsync(id);
var orders = await GetOrdersAsync(id);
var payments = await GetPaymentsAsync(id);

// &#x2705; 并行：快 3 倍
var userTask = GetUserAsync(id);
var ordersTask = GetOrdersAsync(id);
var paymentsTask = GetPaymentsAsync(id);

await Task.WhenAll(userTask, ordersTask, paymentsTask);

var user = await userTask;
var orders = await ordersTask;
var payments = await paymentsTask;
</code></pre>
<h2>取消支持</h2>
<p>长时间运行的操作应该支持取消：</p>
<pre><code>public async Task&lt;IEnumerable&lt;User&gt;&gt; GetUsersAsync(
    CancellationToken cancellationToken = default)
{
    var users = new List&lt;User&gt;();
    
    await foreach (var user in _repository.StreamUsersAsync(cancellationToken))
    {
        cancellationToken.ThrowIfCancellationRequested();
        users.Add(user);
    }
    
    return users;
}

// 使用示例
var cts = new CancellationTokenSource(TimeSpan.FromSeconds(30));

try
{
    var users = await GetUsersAsync(cts.Token);
}
catch (OperationCanceledException)
{
    Console.WriteLine("操作被取消");
}
</code></pre>
<h2>实战案例：异步 HTTP 请求</h2>
<pre><code>public class HttpClientWrapper
{
    private readonly HttpClient _httpClient;
    private readonly ILogger&lt;HttpClientWrapper&gt; _logger;

    public HttpClientWrapper(
        HttpClient httpClient,
        ILogger&lt;HttpClientWrapper&gt; logger)
    {
        _httpClient = httpClient;
        _logger = logger;
    }

    public async Task&lt;T&gt; GetAsync&lt;T&gt;(
        string url,
        CancellationToken cancellationToken = default)
    {
        try
        {
            var response = await _httpClient
                .GetAsync(url, cancellationToken)
                .ConfigureAwait(false);

            response.EnsureSuccessStatusCode();

            var content = await response
                .Content
                .ReadAsStringAsync(cancellationToken)
                .ConfigureAwait(false);

            return JsonSerializer.Deserialize&lt;T&gt;(content);
        }
        catch (HttpRequestException ex)
        {
            _logger.LogError(ex, "HTTP 请求失败: {Url}", url);
            throw;
        }
        catch (JsonException ex)
        {
            _logger.LogError(ex, "JSON 反序列化失败: {Url}", url);
            throw;
        }
    }
}
</code></pre>
<h2>总结</h2>
<p>C# 异步编程的核心原则：</p>
<ul>
<li><strong>始终使用 await</strong>：避免 .Result 或 .Wait() 导致的死锁</li>
<li><strong>避免 async void</strong>：使用 Task 返回类型以便异常处理</li>
<li><strong>优化性能</strong>：使用 ConfigureAwait(false)、ValueTask、并行处理</li>
<li><strong>支持取消</strong>：长时间运行的操作应该接受 CancellationToken</li>
<li><strong>正确处理异常</strong>：使用 try/catch 捕获异步异常</li>
</ul>
<p>掌握这些技巧，你就能写出高效、可靠的异步代码，充分发挥 .NET 平台的并发处理能力。</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>pmset 命令速查</title>
		<link>https://blog.yangyuanping.com/pmset-%e5%91%bd%e4%bb%a4%e9%80%9f%e6%9f%a5/</link>
		
		<dc:creator><![CDATA[peny911]]></dc:creator>
		<pubDate>Fri, 13 Feb 2026 06:10:59 +0000</pubDate>
				<category><![CDATA[Linux Nibbles]]></category>
		<category><![CDATA[未分类]]></category>
		<guid isPermaLink="false">https://blog.yangyuanping.com/?p=1104</guid>

					<description><![CDATA[查看当前电源设置 常用设置 关闭显示器（分钟） 电脑休眠（分钟） 硬盘休眠（分钟） 待机延迟（秒） 混合休眠模 [&#8230;]]]></description>
										<content:encoded><![CDATA[
<h2 class="wp-block-heading" id="查看当前电源设置">查看当前电源设置</h2>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:1.125rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.625rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="复制" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>pmset -g</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #D8DEE9">pmset</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9">g</span></span></code></pre></div>



<h4 class="wp-block-heading" id="常用设置">常用设置</h4>



<h6 class="wp-block-heading" id="关闭显示器（分钟）">关闭显示器（分钟）</h6>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:1.125rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.625rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="复制" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>sudo pmset displaysleep 15</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #D8DEE9">sudo</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">pmset</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">displaysleep</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">15</span></span></code></pre></div>



<h3 class="wp-block-heading" id="电脑休眠（分钟）">电脑休眠（分钟）</h3>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:1.125rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.625rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="复制" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>sudo pmset sleep 30</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #D8DEE9">sudo</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">pmset</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">sleep</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">30</span></span></code></pre></div>



<h3 class="wp-block-heading" id="硬盘休眠（分钟）">硬盘休眠（分钟）</h3>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:1.125rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.625rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="复制" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>sudo pmset disksleep 10</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #D8DEE9">sudo</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">pmset</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">disksleep</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">10</span></span></code></pre></div>



<h3 class="wp-block-heading" id="待机延迟（秒）">待机延迟（秒）</h3>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:1.125rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.625rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="复制" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>sudo pmset standbydelay 10800
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #D8DEE9">sudo</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">pmset</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">standbydelay</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">10800</span></span>
<span class="line"></span></code></pre></div>



<h3 class="wp-block-heading" id="混合休眠模式">混合休眠模式</h3>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:1.125rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.625rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="复制" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>sudo pmset standby 1 # 启用待机
sudo pmset hibernatemode 25 # 混合休眠</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #D8DEE9">sudo</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">pmset</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">standby</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">1</span><span style="color: #D8DEE9FF"> # </span><span style="color: #D8DEE9">启用待机</span></span>
<span class="line"><span style="color: #D8DEE9">sudo</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">pmset</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">hibernatemode</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">25</span><span style="color: #D8DEE9FF"> # </span><span style="color: #D8DEE9">混合休眠</span></span></code></pre></div>



<h2 class="wp-block-heading" id="常用组合">常用组合</h2>



<h3 class="wp-block-heading" id="永不休眠（接电源）">永不休眠（接电源）</h3>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:1.125rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.625rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="复制" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>sudo pmset -c sleep 0 displaysleep 0 disksleep 0</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #D8DEE9">sudo</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">pmset</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9">c</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">sleep</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">displaysleep</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">disksleep</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span></span></code></pre></div>



<h3 class="wp-block-heading" id="电池省电模式">电池省电模式</h3>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:1.125rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.625rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="复制" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>sudo pmset -b sleep 15 displaysleep 5 disksleep 10</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #D8DEE9">sudo</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">pmset</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9">b</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">sleep</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">15</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">displaysleep</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">5</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">disksleep</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">10</span></span></code></pre></div>



<h2 class="wp-block-heading" id="字段说明">字段说明</h2>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>字段</th><th>值</th><th>说明</th></tr></thead><tbody><tr><td><strong>lidwake</strong></td><td>1</td><td>开盖唤醒</td></tr><tr><td><strong>autopoweroff</strong></td><td>0</td><td>自动关机（省电关机）</td></tr><tr><td><strong>lowpowermode</strong></td><td>1</td><td>低电量模式</td></tr><tr><td><strong>standbydelayhigh</strong></td><td>86400</td><td>高电量待机延迟（秒，24小时）</td></tr><tr><td><strong>autopoweroffdelay</strong></td><td>259200</td><td>自动关机延迟（秒，3天）</td></tr><tr><td><strong>proximitywake</strong></td><td>0</td><td>proximity 唤醒</td></tr><tr><td><strong>standby</strong></td><td>0</td><td>待机模式</td></tr><tr><td><strong>standbydelaylow</strong></td><td>10800</td><td>低电量待机延迟（秒，3小时）</td></tr><tr><td><strong>ttyskeepawake</strong></td><td>1</td><td>TTY 保持唤醒</td></tr><tr><td><strong>hibernatemode</strong></td><td>0</td><td>休眠模式（0=禁用）</td></tr><tr><td><strong>powernap</strong></td><td>0</td><td>电源nap</td></tr><tr><td><strong>gpuswitch</strong></td><td>2</td><td>GPU 自动切换</td></tr><tr><td><strong>hibernatefile</strong></td><td>/var/vm/sleepimage</td><td>休眠文件路径</td></tr><tr><td><strong>highstandbythreshold</strong></td><td>50</td><td>高电量待机阈值</td></tr><tr><td><strong>displaysleep</strong></td><td>5</td><td>显示器休眠（分钟）</td></tr><tr><td><strong>womp</strong></td><td>0</td><td>网络唤醒</td></tr><tr><td><strong>networkoversleep</strong></td><td>0</td><td>网络过载休眠</td></tr><tr><td><strong>sleep</strong></td><td>10</td><td>电脑休眠（分钟）</td></tr><tr><td><strong>lessbright</strong></td><td>1</td><td>暗屏时降低亮度</td></tr><tr><td><strong>halfdim</strong></td><td>1</td><td>半亮度休眠</td></tr><tr><td><strong>tcpkeepalive</strong></td><td>1</td><td>TCP 保持连接</td></tr><tr><td><strong>acwake</strong></td><td>0</td><td>电源适配器唤醒</td></tr><tr><td><strong>disksleep</strong></td><td>10</td><td>硬盘休眠（分钟）</td></tr></tbody></table></figure>



<h2 class="wp-block-heading" id="查看所有设置详情">查看所有设置详情</h2>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:1.125rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.625rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="复制" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>pmset -g custom</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #D8DEE9">pmset</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9">g</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">custom</span></span></code></pre></div>



<h2 class="wp-block-heading" id="恢复默认设置">恢复默认设置</h2>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:1.125rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.625rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="复制" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>sudo pmset -a sleep 10 displaysleep 10 disksleep 10</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #D8DEE9">sudo</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">pmset</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9">a</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">sleep</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">10</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">displaysleep</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">10</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">disksleep</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">10</span></span></code></pre></div>



<h3 class="wp-block-heading" id="禁用休眠（适合常开机）">禁用休眠（适合常开机）</h3>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:1.125rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.625rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="复制" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>sudo pmset -a sleep 0 disksleep 0
udo pmset -a hibernatemode 0</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #D8DEE9">sudo</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">pmset</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9">a</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">sleep</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">disksleep</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span></span>
<span class="line"><span style="color: #D8DEE9">udo</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">pmset</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9">a</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">hibernatemode</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span></span></code></pre></div>



<h3 class="wp-block-heading" id="查看唤醒原因">查看唤醒原因</h3>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:1.125rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.625rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="复制" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly># 查看当前阻止系统 / 显示器睡眠的所有电源断言（Power Assertions），快速定位 Mac 无法自动休眠的原因。
pmset -g assertions 

# 查看唤醒原因
pmset -g | grep wake</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #D8DEE9FF"># </span><span style="color: #D8DEE9">查看当前阻止系统</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">/</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">显示器睡眠的所有电源断言</span><span style="color: #D8DEE9FF">（</span><span style="color: #D8DEE9">Power</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">Assertions</span><span style="color: #D8DEE9FF">），</span><span style="color: #D8DEE9">快速定位</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">Mac</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">无法自动休眠的原因</span><span style="color: #D8DEE9FF">。</span></span>
<span class="line"><span style="color: #D8DEE9">pmset</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9">g</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">assertions</span><span style="color: #D8DEE9FF"> </span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF"># </span><span style="color: #D8DEE9">查看唤醒原因</span></span>
<span class="line"><span style="color: #D8DEE9">pmset</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9">g</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">|</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">grep</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">wake</span></span></code></pre></div>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>需求</th><th>命令</th><th></th></tr></thead><tbody><tr><td>看唤醒设置</td><td><code>pmset -g</code></td><td>`grep wake`</td></tr><tr><td>看最近唤醒原因</td><td><code>pmset -g log</code></td><td>`grep -i &#8220;wake reason&#8221;`</td></tr><tr><td>看定时唤醒</td><td><code>pmset -g sched</code></td><td></td></tr><tr><td>查阻止睡眠的进程</td><td><code>pmset -g assertions</code></td><td></td></tr></tbody></table></figure>



<h2 class="wp-block-heading" id="参数说明">参数说明</h2>



<ul class="wp-block-list">
<li><code>-a</code> 所有电源模式</li>



<li><code>-c</code> 电源适配器（接充电器）</li>



<li><code>-b</code> 电池模式</li>



<li><code>-u</code> UPS 模式</li>
</ul>



<h2 class="wp-block-heading" id="hibernatemode-取值">hibernatemode 取值</h2>



<ul class="wp-block-list">
<li><code>0</code> &#8211; 内存休眠，唤醒快</li>



<li><code>1</code> &#8211; 安全休眠到磁盘</li>



<li><code>3</code> &#8211; 内存+磁盘混合（默认）</li>



<li><code>25</code> &#8211; 强制休眠到磁盘</li>
</ul>



<h2 class="wp-block-heading" id="相关命令">相关命令</h2>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:1.125rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.625rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="复制" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly># 立即锁屏
pmset displaysleepnow

# 查看电池状态
pmset -g batt

# 查看唤醒原因
pmset -g wake</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #D8DEE9FF"># </span><span style="color: #D8DEE9">立即锁屏</span></span>
<span class="line"><span style="color: #D8DEE9">pmset</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">displaysleepnow</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF"># </span><span style="color: #D8DEE9">查看电池状态</span></span>
<span class="line"><span style="color: #D8DEE9">pmset</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9">g</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">batt</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF"># </span><span style="color: #D8DEE9">查看唤醒原因</span></span>
<span class="line"><span style="color: #D8DEE9">pmset</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9">g</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">wake</span></span></code></pre></div>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p><strong>来源</strong>: macOS 系统命令</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>OpenRTB 协议实战：程序化广告的通信语言</title>
		<link>https://blog.yangyuanping.com/openrtb-%e5%8d%8f%e8%ae%ae%e5%ae%9e%e6%88%98%ef%bc%9a%e7%a8%8b%e5%ba%8f%e5%8c%96%e5%b9%bf%e5%91%8a%e7%9a%84%e9%80%9a%e4%bf%a1%e8%af%ad%e8%a8%80/</link>
		
		<dc:creator><![CDATA[peny911]]></dc:creator>
		<pubDate>Thu, 12 Feb 2026 15:38:32 +0000</pubDate>
				<category><![CDATA[未分类]]></category>
		<guid isPermaLink="false">https://blog.yangyuanping.com/?p=1079</guid>

					<description><![CDATA[OpenRTB 协议实战：程序化广告的通信语言 在程序化广告生态中，DSP（需求方平台）、ADX（广告交易平台 [&#8230;]]]></description>
										<content:encoded><![CDATA[<h1>OpenRTB 协议实战：程序化广告的通信语言</h1>
<p>在程序化广告生态中，<strong>DSP（需求方平台）</strong>、<strong>ADX（广告交易平台）</strong> 与 <strong>SSP（供应方平台）</strong> 之间的实时通信是整个竞价链路的核心。而这套通信机制的基础，正是 <strong>OpenRTB 协议</strong>。</p>
<p>本文将从协议结构、关键字段、实际案例三个维度，帮你快速掌握 OpenRTB 的核心要点。</p>
<h2>一、为什么需要 OpenRTB？</h2>
<p>传统广告投放依赖人工操作，效率低、粒度粗。而程序化广告追求 <strong>毫秒级响应</strong>、<strong>实时竞价</strong>、<strong>精准定向</strong>，必须有一套标准化的数据交换格式。</p>
<p>OpenRTB（Real-Time Bidding）由 <strong>IAB（Interactive Advertising Bureau）</strong> 主导制定，目前主流版本是 <strong>OpenRTB 2.5</strong>。</p>
<p><strong>核心价值：</strong></p>
<ul>
<li>统一数据格式，降低对接成本</li>
<li>支持实时竞价，毫秒级响应</li>
<li>丰富的扩展字段，满足业务定制化需求</li>
</ul>
<h2>二、协议结构一览</h2>
<p>一次完整的竞价流程涉及两个核心请求：</p>
<h3>1. Bid Request（出价请求）— ADX → DSP</h3>
<p>这是 ADX 向 DSP 发送的&quot;竞价邀请&quot;，包含广告位信息、用户特征、投放限制等。</p>
<pre><code class="language-json">{
  "id": "abc123-uuid",
  "tmax": 120,
  "device": {
    "ua": "Mozilla/5.0...",
    "ip": "203.0.113.42",
    "geo": {
      "country": "CHN",
      "city": "Dalian"
    }
  },
  "user": {
    "id": "user_xyz789",
    "data": [{
      "segment": [{"id": "interest_tech"}]
    }]
  },
  "imp": [{
    "id": "1",
    "bidfloor": 0.5,
    "banner": {
      "w": 300,
      "h": 250,
      "mimes": ["image/jpeg", "image/png"]
    }
  }],
  "site": {
    "id": "site_001",
    "name": "News Portal",
    "publisher": {"id": "pub_123"}
  }
}</code></pre>
<p><strong>关键字段解读：</strong></p>
<ul>
<li>&lt;code&gt;id&lt;/code&gt;: 唯一请求标识，用于关联后续响应</li>
<li>&lt;code&gt;tmax&lt;/code&gt;: 超时时间（毫秒），DSP 必须在此时限内返回响应</li>
<li>&lt;code&gt;device&lt;/code&gt;: 设备信息（UA、IP、地理位置），用于用户定向</li>
<li>&lt;code&gt;imp&lt;/code&gt;: 广告展示请求列表，每个 &lt;code&gt;imp&lt;/code&gt; 代表一个广告位</li>
<li>&lt;code&gt;bidfloor&lt;/code&gt;: 最低出价（CPM）</li>
</ul>
<h3>2. Bid Response（出价响应）— DSP → ADX</h3>
<p>DSP 收到请求后，经过竞价决策，返回出价结果。</p>
<pre><code class="language-json">{
  "id": "abc123-uuid",
  "seatbid": [{
    "bid": [{
      "id": "bid_001",
      "impid": "1",
      "price": 1.25,
      "adm": "&lt;html&gt;&lt;img src=https://ad.example.com/creative.jpg/&gt;&lt;/html&gt;",
      "crid": "creative_888",
      "nurl": "https://dsp.example.com/win?price=${AUCTION_PRICE}"
    }]
  }],
  "bidid": "bid_response_001"
}</code></pre>
<p><strong>关键字段解读：</strong></p>
<ul>
<li>&lt;code&gt;seatbid&lt;/code&gt;: 出价席位列表</li>
<li>&lt;code&gt;price&lt;/code&gt;: 出价金额（CPM）</li>
<li>&lt;code&gt;adm&lt;/code&gt;: 广告物料（HTML、图片、VAST 等）</li>
<li>&lt;code&gt;crid&lt;/code&gt;: 创意 ID，用于素材追踪</li>
<li>&lt;code&gt;nurl&lt;/code&gt;: 竞价获胜通知地址，&lt;code&gt;${AUCTION_PRICE}&lt;/code&gt; 会被替换为实际成交价</li>
</ul>
<h2>三、实战：竞价超时处理</h2>
<p>在 RTB 项目中，<strong>超时控制</strong>是性能优化的关键。</p>
<p>根据行业实践和 MEMORY.md 中记录的约束要求：</p>
<ul>
<li><strong>Bid Request 处理 &lt; 30ms</strong></li>
<li><strong>Redis 读写 &lt; 5ms</strong></li>
</ul>
<p><strong>超时处理代码示例（C#）：</strong></p>
<pre><code class="language-csharp">public async Task&lt;BidResponse&gt; HandleBidRequestAsync(BidRequest request, CancellationToken ct)
{
    // 创建超时任务
    var timeoutTask = Task.Delay(25, ct); // 预留 5ms 余量

    // 并行执行竞价逻辑
    var biddingTask = ExecuteBiddingAsync(request, ct);

    // 任一任务完成即返回
    var completedTask = await Task.WhenAny(biddingTask, timeoutTask);

    if (completedTask == timeoutTask)
    {
        // 超时，返回默认响应或空响应
        _logger.LogWarning("Bid request {RequestId} timed out", request.Id);
        return CreateDefaultResponse(request.Id);
    }

    return await biddingTask;
}</code></pre>
<p><strong>Redis 缓存优化策略：</strong></p>
<pre><code class="language-csharp">public async Task&lt;UserProfile&gt; GetUserProfileAsync(string userId)
{
    var cacheKey = $"user:{userId}";

    // 先查 Redis（目标 &lt; 5ms）
    var cached = await _redisDatabase.StringGetAsync(cacheKey);
    if (cached.HasValue)
    {
        return JsonSerializer.Deserialize&lt;UserProfile&gt;(cached);
    }

    // 缓存未命中，查 DB 后回填
    var profile = await _repository.GetUserProfileAsync(userId);

    // 异步回写缓存
    _ = _redisDatabase.StringSetAsync(cacheKey, 
        JsonSerializer.Serialize(profile), 
        TimeSpan.FromMinutes(5));

    return profile;
}</code></pre>
<h2>四、注意事项</h2>
<ol>
<li><strong>协议版本兼容性</strong>：不同 ADX 可能使用不同版本的 OpenRTB，需做好版本适配层</li>
<li><strong>安全传输</strong>：生产环境必须使用 HTTPS/TLS，防止请求被篡改</li>
<li><strong>日志脱敏</strong>：用户 IP、设备 ID 等敏感信息在日志中需脱敏处理</li>
<li><strong>幂等性</strong>：ID 生成和请求处理需保证幂等，避免重复计费</li>
</ol>
<h2>五、总结</h2>
<p>OpenRTB 是程序化广告的&quot;通用语言&quot;，掌握其协议结构和实战用法，是开发 DSP/ADX 系统的基础。建议结合实际项目（如 Google Authorized Buyers、OpenRTB 规范文档）深入学习。</p>
<hr />
<p><strong>参考来源：</strong></p>
<ul>
<li>IAB OpenRTB 2.5 Specification</li>
<li>Google Authorized Buyers API Documentation</li>
</ul>
<blockquote>
<p>关注我，获取更多 RTB 实战经验与 .NET 性能优化技巧。</p>
</blockquote>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Mac 中使用 VSCode 开发 Framework 项目指南</title>
		<link>https://blog.yangyuanping.com/mac-%e4%b8%ad%e4%bd%bf%e7%94%a8-vscode-%e5%bc%80%e5%8f%91-framework-%e9%a1%b9%e7%9b%ae%e6%8c%87%e5%8d%97/</link>
		
		<dc:creator><![CDATA[peny911]]></dc:creator>
		<pubDate>Tue, 23 Dec 2025 14:19:57 +0000</pubDate>
				<category><![CDATA[未分类]]></category>
		<category><![CDATA[.Net]]></category>
		<category><![CDATA[Mac]]></category>
		<category><![CDATA[VSCode]]></category>
		<guid isPermaLink="false">https://blog.yangyuanping.com/?p=1072</guid>

					<description><![CDATA[前置要求 对于 .NET Framework 4.5.2 项目，在 macOS 上需要使用 Mono 来运行。 [&#8230;]]]></description>
										<content:encoded><![CDATA[<h2>前置要求</h2>
<p>对于 .NET Framework 4.5.2 项目，在 macOS 上需要使用 Mono 来运行。</p>
<h2>第一步：安装必需工具</h2>
<h3>1. 安装 Mono</h3>
<pre><code class="language-bash">brew install mono</code></pre>
<p>验证安装：</p>
<pre><code class="language-bash">mono --version</code></pre>
<h3>2. 安装 NuGet</h3>
<pre><code class="language-bash">brew install nuget</code></pre>
<h3>3. 安装 MSBuild (包含在 Mono 中)</h3>
<p>验证安装：</p>
<pre><code class="language-bash">msbuild -version</code></pre>
<h3>4. 安装 XSP (Mono 的 Web 服务器)</h3>
<pre><code class="language-bash">brew install xsp</code></pre>
<h2>第二步：安装 VSCode 扩展</h2>
<p>在 VSCode 中安装以下扩展（已在 &lt;code&gt;.vscode/extensions.json&lt;/code&gt; 中推荐）：</p>
<ol>
<li><strong>C# Dev Kit</strong> &#8211; 微软官方 C# 支持</li>
<li><strong>C#</strong> &#8211; OmniSharp 语言服务</li>
<li><strong>.NET Test Explorer</strong> &#8211; 测试资源管理器</li>
</ol>
<p>重启 VSCode 以激活扩展。</p>
<h2>第三步：构建项目</h2>
<h3>方法 1：使用 VSCode 任务（推荐）</h3>
<ol>
<li>按 &lt;code&gt;Cmd+Shift+P&lt;/code&gt; 打开命令面板</li>
<li>选择 &lt;code&gt;Tasks: Run Task&lt;/code&gt;</li>
<li>选择 &lt;code&gt;构建解决方案 (Debug)&lt;/code&gt;</li>
</ol>
<h3>方法 2：使用终端命令</h3>
<pre><code class="language-bash"># 恢复 NuGet 包
nuget restore &lt;Solution-Name&gt;.sln

# 构建项目
msbuild &lt;Solution-Name&gt;.sln /p:Configuration=Debug</code></pre>
<h2>第四步：运行和调试</h2>
<h3>运行 WebAPI 项目</h3>
<h4>方法 1：使用 XSP（Mono Web 服务器）</h4>
<pre><code class="language-bash"># 在终端中运行
xsp4 --port=&lt;PORT&gt; --path=&lt;ProjectName&gt;</code></pre>
<p>然后访问：<a href="http://localhost:23985/api/message">http://localhost:23985/api/message</a></p>
<h4>方法 2：使用 VSCode 任务</h4>
<ol>
<li>按 &lt;code&gt;Cmd+Shift+P&lt;/code&gt;</li>
<li>选择 &lt;code&gt;Tasks: Run Task&lt;/code&gt;</li>
<li>选择 &lt;code&gt;运行 WebAPI (XSP)&lt;/code&gt;</li>
</ol>
<h3>调试代码</h3>
<ol>
<li>在代码中设置断点（点击行号左侧）</li>
<li>按 &lt;code&gt;F5&lt;/code&gt; 或点击调试面板的&quot;开始调试&quot;</li>
<li>选择配置：&lt;code&gt;调试 WebAPI (Mono)&lt;/code&gt;</li>
</ol>
<h3>运行单元测试</h3>
<h4>使用 VSCode 任务：</h4>
<ol>
<li>按 &lt;code&gt;Cmd+Shift+P&lt;/code&gt;</li>
<li>选择 &lt;code&gt;Tasks: Run Task&lt;/code&gt;</li>
<li>选择 &lt;code&gt;运行单元测试&lt;/code&gt;</li>
</ol>
<h4>使用命令行：</h4>
<pre><code class="language-bash"># 首先需要安装 NUnit Console Runner（如果还没有）
nuget install NUnit.ConsoleRunner -Version 3.15.0 -OutputDirectory packages

# 运行测试
mono packages/NUnit.ConsoleRunner.3.15.0/tools/nunit3-console.exe \
  &lt;TestProjectName&gt;/bin/Debug/&lt;TestProjectName&gt;.dll</code></pre>
<h2>常用 VSCode 快捷键</h2>
<ul>
<li>&lt;code&gt;Cmd+Shift+B&lt;/code&gt; &#8211; 运行默认构建任务</li>
<li>&lt;code&gt;F5&lt;/code&gt; &#8211; 开始调试</li>
<li>&lt;code&gt;Shift+F5&lt;/code&gt; &#8211; 停止调试</li>
<li>&lt;code&gt;F9&lt;/code&gt; &#8211; 切换断点</li>
<li>&lt;code&gt;F10&lt;/code&gt; &#8211; 单步跳过</li>
<li>&lt;code&gt;F11&lt;/code&gt; &#8211; 单步进入</li>
<li>&lt;code&gt;Cmd+K Cmd+D&lt;/code&gt; &#8211; 格式化文档</li>
</ul>
<h2>常见问题</h2>
<h3>1. Mono 找不到程序集</h3>
<p>确保已运行 &lt;code&gt;nuget restore&lt;/code&gt; 来恢复所有依赖包。</p>
<h3>2. MSBuild 失败</h3>
<p>检查 Mono 版本是否支持 .NET Framework 4.5.2：</p>
<pre><code class="language-bash">mono --version</code></pre>
<p>需要 Mono 5.0 或更高版本。</p>
<h3>3. XSP 无法启动</h3>
<p>确保端口 23985 未被占用：</p>
<pre><code class="language-bash">lsof -i :23985</code></pre>
<h3>4. OmniSharp 无法加载项目</h3>
<p>在 VSCode 设置中确保：</p>
<ul>
<li>&lt;code&gt;omnisharp.useModernNet&lt;/code&gt; 设置为 &lt;code&gt;false&lt;/code&gt;</li>
<li>&lt;code&gt;omnisharp.monoPath&lt;/code&gt; 指向正确的 Mono 安装路径</li>
</ul>
<h2>已知限制</h2>
<ol>
<li><strong>调试功能受限</strong>：Mono 的调试体验不如 Windows 上的 Visual Studio</li>
<li><strong>性能差异</strong>：Mono 运行性能可能低于 Windows .NET Framework</li>
<li><strong>某些 API 不可用</strong>：部分 Windows 特定的 API 在 Mono 上不支持</li>
</ol>
<h2>建议</h2>
<p>对于生产环境部署，建议：</p>
<ol>
<li>在 Windows Server 上使用 IIS 托管</li>
<li>或考虑将项目迁移到 .NET 6/8 以获得跨平台支持</li>
</ol>
<h2>迁移到现代 .NET 的好处</h2>
<p>如果你计划长期维护此项目，可以考虑迁移到 .NET 8：</p>
<ul>
<li>原生跨平台支持（无需 Mono）</li>
<li>更好的性能</li>
<li>现代化的工具链</li>
<li>长期支持（LTS）</li>
</ul>
<p>迁移步骤请参考：<a href="https://docs.microsoft.com/zh-cn/aspnet/core/migration/">https://docs.microsoft.com/zh-cn/aspnet/core/migration/</a></p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>本地开发环境的自签名 HTTPS 证书不被信任(net::ERR_CERT_AUTHORITY_INVALID)</title>
		<link>https://blog.yangyuanping.com/%e6%9c%ac%e5%9c%b0%e5%bc%80%e5%8f%91%e7%8e%af%e5%a2%83%e7%9a%84%e8%87%aa%e7%ad%be%e5%90%8d-https-%e8%af%81%e4%b9%a6%e4%b8%8d%e8%a2%ab%e4%bf%a1%e4%bb%bbneterr_cert_authority_invalid/</link>
		
		<dc:creator><![CDATA[peny911]]></dc:creator>
		<pubDate>Fri, 19 Dec 2025 05:02:49 +0000</pubDate>
				<category><![CDATA[未分类]]></category>
		<category><![CDATA[ERR_CERT_AUTHORITY_INVALID]]></category>
		<category><![CDATA[https]]></category>
		<guid isPermaLink="false">https://blog.yangyuanping.com/?p=1053</guid>

					<description><![CDATA[问题描述 本地运行后端项目后，通过浏览器调用 API 时提示： POST https://&#60;ip&#62; [&#8230;]]]></description>
										<content:encoded><![CDATA[<h2>问题描述</h2>
<p>本地运行后端项目后，通过浏览器调用 API 时提示：</p>
<pre><code> POST https://&lt;ip&gt;:&lt;port&gt;/path net::ERR_CERT_AUTHORITY_INVALID</code></pre>
<p><strong>原因</strong>：本地开发环境使用的是 .NET 自签名 HTTPS 证书，浏览器默认不信任该证书。</p>
<h2>解决方案</h2>
<h3>方案 1：信任 .NET 开发证书（推荐）</h3>
<pre><code class="language-bash"> dotnet dev-certs https --trust</code></pre>
<p>如果提示证书已存在但不信任，先清理再重新生成：</p>
<pre><code class="language-bash"> dotnet dev-certs https --clean
 dotnet dev-certs https --trust</code></pre>
<blockquote>
<p>一次性解决，之后所有 .NET 本地开发项目都会自动信任。</p>
</blockquote>
<h3>方案 2：使用 HTTP 端口</h3>
<p>修改前端 SDK 的开发环境端点，使用 HTTP 端口 &lt;code&gt;5085&lt;/code&gt; 而非 HTTPS 端口 &lt;code&gt;7218&lt;/code&gt;：</p>
<pre><code class="language-javascript"> // webpack.config.js 或 sdk.js 中
 resolveEndpoint: 'http://&lt;ip&gt;:&lt;port&gt;/path'</code></pre>
<h3>方案 3：浏览器手动信任</h3>
<ol>
<li>直接访问 &lt;code&gt;https://&lt;ip&gt;:&lt;port&gt;/swagger&lt;/code&gt;</li>
<li>浏览器会提示&quot;不安全&quot;，点击&quot;高级&quot; → &quot;继续访问&quot;</li>
<li>
<p>之后该证书在当前浏览器会话中被临时信任</p>
<h3>方案 4：Chrome 启动参数（临时）</h3>
<pre><code class="language-bash"># macOS
open -a "Google Chrome" --args --ignore-certificate-errors --ignore-urlfetcher-cert-requests

# Windows
chrome.exe --ignore-certificate-errors --ignore-urlfetcher-cert-requests</code></pre>
<blockquote>
<p>注意：此方式会忽略所有证书错误，仅用于开发调试。</p>
</blockquote>
</li>
</ol>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>TencentOS Server 4 安装 dotnet 运行时</title>
		<link>https://blog.yangyuanping.com/tencentos-server-4-%e5%ae%89%e8%a3%85-dotnet-%e8%bf%90%e8%a1%8c%e6%97%b6/</link>
		
		<dc:creator><![CDATA[peny911]]></dc:creator>
		<pubDate>Wed, 17 Dec 2025 18:39:49 +0000</pubDate>
				<category><![CDATA[Linux Nibbles]]></category>
		<category><![CDATA[.Net]]></category>
		<category><![CDATA[Server]]></category>
		<category><![CDATA[TencentOS]]></category>
		<guid isPermaLink="false">https://blog.yangyuanping.com/?p=1051</guid>

					<description><![CDATA[TencentOS Server 4 基于 RHEL 8，使用 dnf： 添加 Microsoft 仓库 su [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>TencentOS Server 4 基于 RHEL 8，使用 dnf：</p>
<h1>添加 Microsoft 仓库</h1>
<p>sudo rpm -Uvh <a href="https://packages.microsoft.com/config/centos/8/packages-microsoft-prod.rpm">https://packages.microsoft.com/config/centos/8/packages-microsoft-prod.rpm</a></p>
<h1>安装运行时</h1>
<p>sudo dnf install -y aspnetcore-runtime-8.0</p>
<h1>验证</h1>
<p>dotnet &#8211;list-runtimes</p>
<p>如果上面的源不可用，可以用脚本安装：</p>
<h1>下载安装脚本</h1>
<p>curl -sSL <a href="https://dot.net/v1/dotnet-install.sh">https://dot.net/v1/dotnet-install.sh</a> -o dotnet-install.sh<br />
chmod +x dotnet-install.sh</p>
<h1>安装到 /usr/share/dotnet（全局）</h1>
<p>sudo ./dotnet-install.sh &#8211;channel 8.0 &#8211;runtime aspnetcore &#8211;install-dir /usr/share/dotnet</p>
<h1>创建软链接</h1>
<p>sudo ln -sf /usr/share/dotnet/dotnet /usr/bin/dotnet</p>
<h1>验证</h1>
<p>dotnet &#8211;list-runtimes</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Nginx + .NET 压测与连接问题排查总结</title>
		<link>https://blog.yangyuanping.com/nginx-net-%e5%8e%8b%e6%b5%8b%e4%b8%8e%e8%bf%9e%e6%8e%a5%e9%97%ae%e9%a2%98%e6%8e%92%e6%9f%a5%e6%80%bb%e7%bb%93/</link>
		
		<dc:creator><![CDATA[peny911]]></dc:creator>
		<pubDate>Wed, 17 Dec 2025 16:41:10 +0000</pubDate>
				<category><![CDATA[Linux Nibbles]]></category>
		<category><![CDATA[.Net]]></category>
		<category><![CDATA[Server]]></category>
		<guid isPermaLink="false">https://blog.yangyuanping.com/?p=1049</guid>

					<description><![CDATA[Nginx + .NET 压测与连接问题排查总结 本文是一次完整的 线上问题排查 + 架构修复 + 压力测试验 [&#8230;]]]></description>
										<content:encoded><![CDATA[<h1>Nginx + .NET 压测与连接问题排查总结</h1>
<blockquote>
<p>本文是一次完整的 <strong>线上问题排查 + 架构修复 + 压力测试验证</strong> 的工程级总结，可作为 <strong>事故复盘、容量评估报告、运维 Runbook</strong> 使用。</p>
</blockquote>
<hr />
<h2>一、问题背景与现象</h2>
<h3>初始问题</h3>
<ul>
<li>
<p>Nginx 错误日志频繁出现：</p>
<pre><code class="language-text">upstream timed out (110: Connection timed out) while connecting to upstream</code></pre>
</li>
<li>
<p>请求多为：</p>
<pre><code class="language-text">OPTIONS /api/Ads/resolve HTTP/2.0</code></pre>
</li>
<li>上游地址：&lt;code&gt;127.0.0.1:5085&lt;/code&gt;（.NET Kestrel）</li>
</ul>
<h3>同时观测到的内核异常</h3>
<ul>
<li>&lt;code&gt;listen queue overflow&lt;/code&gt;</li>
<li>&lt;code&gt;SYNs to LISTEN sockets dropped&lt;/code&gt;</li>
<li>&lt;code&gt;SYN cookies sent&lt;/code&gt;</li>
<li>&lt;code&gt;TCPTimeWaitOverflow&lt;/code&gt;</li>
</ul>
<h3>直接影响</h3>
<ul>
<li>Nginx 无法连接本机上游</li>
<li>API 出现大量失败</li>
<li>高并发下服务不可用</li>
</ul>
<hr />
<h2>二、根因分析（结论级）</h2>
<h3>1&#x20e3; Nginx → Kestrel 连接模型错误（<strong>核心根因</strong>）</h3>
<p>在 &lt;code&gt;location /&lt;/code&gt; 中错误地配置了：</p>
<pre><code class="language-nginx">proxy_set_header Connection "upgrade";</code></pre>
<p>导致：</p>
<ul>
<li>所有普通 HTTP 请求被迫使用 &lt;code&gt;Connection: upgrade&lt;/code&gt;</li>
<li>Keepalive 失效</li>
<li>每个请求都建立/断开 TCP 连接</li>
</ul>
<p><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f449.png" alt="👉" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <strong>直接引发短连接风暴</strong></p>
<hr />
<h3>2&#x20e3; OPTIONS 预检请求被放大</h3>
<ul>
<li>外站（如豆瓣）触发大量跨域请求</li>
<li>每个请求都会先发 &lt;code&gt;OPTIONS&lt;/code&gt;</li>
<li>&lt;code&gt;OPTIONS&lt;/code&gt; 被转发到上游应用</li>
</ul>
<p>在短连接模型下形成 <strong>连接洪峰</strong>。</p>
<hr />
<h3>3&#x20e3; 内核层连锁反应</h3>
<ul>
<li>SYN backlog 被打满</li>
<li>accept queue 溢出</li>
<li>内核开始丢 SYN / 启用 SYN cookies</li>
<li>Nginx 连接上游直接超时（110）</li>
</ul>
<hr />
<h2>三、关键修复措施（工程级）</h2>
<h3>1&#x20e3; 引入 upstream keepalive（<strong>最关键修复</strong>）</h3>
<p>在 &lt;code&gt;http {}&lt;/code&gt; 作用域中新增：</p>
<pre><code class="language-nginx">upstream eaglex_upstream {
    server 127.0.0.1:5085;
    keepalive 256;
}</code></pre>
<p>统一使用：</p>
<pre><code class="language-nginx">proxy_pass http://eaglex_upstream;
proxy_http_version 1.1;
proxy_set_header Connection "";</code></pre>
<hr />
<h3>2&#x20e3; 修正 Connection 头使用方式（<strong>非常关键</strong>）</h3>
<ul>
<li>
<p><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/274c.png" alt="❌" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 禁止在普通 HTTP 路径中使用：</p>
<pre><code class="language-nginx">Connection: upgrade</code></pre>
</li>
<li><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 只在 <strong>WebSocket 专用 location</strong> 中使用 upgrade</li>
</ul>
<hr />
<h3>3&#x20e3; 在 Nginx 层直接短路 OPTIONS 预检</h3>
<pre><code class="language-nginx">location = /api/Ads/resolve {
    if ($request_method = OPTIONS) {
        add_header Access-Control-Allow-Origin $http_origin always;
        add_header Access-Control-Allow-Methods "GET,POST,OPTIONS" always;
        add_header Access-Control-Allow-Headers "Content-Type,Authorization" always;
        add_header Access-Control-Max-Age 86400 always;
        return 204;
    }
    proxy_pass http://eaglex_upstream;
}</code></pre>
<p><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f449.png" alt="👉" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <strong>彻底消除预检请求对上游的压力放大</strong></p>
<hr />
<h3>4&#x20e3; 缩短 proxy_connect_timeout（防止雪崩）</h3>
<pre><code class="language-nginx">proxy_connect_timeout 2s;</code></pre>
<p>避免 Nginx worker 在连接失败时长时间阻塞。</p>
<hr />
<h2>四、压测阶段的验证结论</h2>
<h3>压测过程中观测到的健康状态</h3>
<ul>
<li>&lt;code&gt;.NET&lt;/code&gt; CPU：≈ 260%–300%（4C 机器，尚有余量）</li>
<li>Nginx CPU：≈ 10%–20%</li>
<li>&lt;code&gt;ksoftirqd&lt;/code&gt;：极低</li>
<li>
<p>TCP 状态：</p>
<pre><code class="language-text">estab ≈ 3000
timewait ≈ 30
orphan = 0</code></pre>
</li>
<li>
<p>内核累计计数在压测前后 <strong>完全无增长</strong>：</p>
<ul>
<li>listen queue overflow</li>
<li>SYN dropped</li>
<li>TCPTimeWaitOverflow</li>
</ul>
</li>
</ul>
<h3>明确结论</h3>
<blockquote>
<p><strong>连接层 / Nginx / 内核 TCP 已完全稳定，系统瓶颈成功转移至 .NET 应用 CPU 层。</strong></p>
</blockquote>
<hr />
<h2>五、错误日志的两类问题区分（重要）</h2>
<h3>A. &lt;code&gt;110 Connection timed out&lt;/code&gt;</h3>
<pre><code class="language-text">while connecting to upstream</code></pre>
<ul>
<li>含义：连接队列 / accept / backlog 问题</li>
<li>根因：连接模型错误</li>
<li><strong>已在本次修复中解决</strong></li>
</ul>
<hr />
<h3>B. &lt;code&gt;111 Connection refused&lt;/code&gt;</h3>
<pre><code class="language-text">connect() failed (111: Connection refused)</code></pre>
<ul>
<li>含义：上游端口当时 <strong>没有进程在监听</strong></li>
<li>
<p>可能原因：</p>
<ul>
<li>dotnet 进程崩溃</li>
<li>被 OOM killer 杀死</li>
<li>重启 / 发布</li>
</ul>
</li>
</ul>
<p><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f449.png" alt="👉" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 属于 <strong>上游进程稳定性问题</strong>，与 backlog 无关。</p>
<hr />
<h2>六、压测与日常排障常用监控命令清单</h2>
<h3>1&#x20e3; TCP 全局状态（必看）</h3>
<pre><code class="language-bash">ss -s</code></pre>
<p>关注：&lt;code&gt;estab / timewait / orphan&lt;/code&gt;</p>
<hr />
<h3>2&#x20e3; 上游端口连接数（Nginx → Kestrel）</h3>
<pre><code class="language-bash">ss -ant | awk '$4=="127.0.0.1:5085"{c++} END{print c}'</code></pre>
<hr />
<h3>3&#x20e3; 上游连接状态分布</h3>
<pre><code class="language-bash">ss -ant | awk '$4=="127.0.0.1:5085"{print $1}' | sort | uniq -c | sort -nr</code></pre>
<hr />
<h3>4&#x20e3; 内核是否再次被打爆（差分判断）</h3>
<pre><code class="language-bash">netstat -s | egrep -i 'listen queue|SYNs to LISTEN|SYN cookies|TCPTimeWaitOverflow'</code></pre>
<blockquote>
<p>必须用 <strong>前后对比</strong> 判断是否仍在发生。</p>
</blockquote>
<hr />
<h3>5&#x20e3; Nginx 错误日志关键字</h3>
<pre><code class="language-bash">tail -n 200 /www/wwwlogs/eaglex_ads_api.error.log | egrep -i 'timed out|refused|502|504'</code></pre>
<hr />
<h3>6&#x20e3; 上游进程是否存活 / 是否重启</h3>
<pre><code class="language-bash">ps -p &lt;dotnet_pid&gt; -o pid,etimes,%cpu,%mem,cmd
ss -lntp | grep 5085</code></pre>
<hr />
<h3>7&#x20e3; OOM / 内核杀进程检查</h3>
<pre><code class="language-bash">dmesg -T | egrep -i 'oom|killed process'
journalctl -k | egrep -i 'oom|killed'</code></pre>
<hr />
<h3>8&#x20e3; .NET 运行时指标（强烈推荐）</h3>
<pre><code class="language-bash">dotnet-counters monitor System.Runtime --process-id &lt;pid&gt;</code></pre>
<p>关注：</p>
<ul>
<li>CPU Usage</li>
<li>ThreadPool Queue Length</li>
<li>% Time in GC</li>
</ul>
<hr />
<h2>七、最终工程级结论（可直接写入文档）</h2>
<blockquote>
<p>本次问题的根因是 Nginx → Kestrel 连接模型错误（短连接 + OPTIONS 预检放大），导致 TCP listen queue 溢出与 upstream connect timeout。</p>
<p>通过引入 upstream keepalive、修正 Connection 头、在 Nginx 层短路 CORS 预检，并配合合理的超时配置，连接层问题已完全消除。</p>
<p>压测结果表明：系统当前瓶颈已转移至 .NET 应用 CPU 层，TCP 与代理层稳定可靠，具备可预测的容量上限。</p>
</blockquote>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>从 Git 历史中删除敏感数据</title>
		<link>https://blog.yangyuanping.com/%e4%bb%8e-git-%e5%8e%86%e5%8f%b2%e4%b8%ad%e5%88%a0%e9%99%a4%e6%95%8f%e6%84%9f%e6%95%b0%e6%8d%ae/</link>
		
		<dc:creator><![CDATA[peny911]]></dc:creator>
		<pubDate>Wed, 26 Nov 2025 18:01:34 +0000</pubDate>
				<category><![CDATA[未分类]]></category>
		<category><![CDATA[git]]></category>
		<guid isPermaLink="false">https://blog.yangyuanping.com/?p=1041</guid>

					<description><![CDATA[当敏感信息（如密码、密钥、私人域名等）被提交到 Git 仓库后，即使后续提交中删除了这些内容，它们仍然存在于  [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>当敏感信息（如密码、密钥、私人域名等）被提交到 Git 仓库后，即使后续提交中删除了这些内容，它们仍然存在于 Git 历史记录中。本文介绍如何彻底清除这些敏感数据。</p>
<h2>问题场景</h2>
<ul>
<li>不小心提交了 API 密钥、密码</li>
<li>配置文件中包含真实域名或个人信息</li>
<li>已推送到 GitHub 等公开仓库</li>
</ul>
<h2>解决方案&#8217;&quot;</h2>
<h3>方法一：使用 git filter-branch（内置工具）</h3>
<p>适用于替换历史中所有提交的某个文件内容。</p>
<pre><code class="language-bash"># 1. 暂存当前未提交的更改
git stash'"

# 2. 替换历史中所有 README.md 文件里的敏感内容
FILTER_BRANCH_SQUELCH_WARNING=1 git filter-branch --force --tree-filter \
  "find . -name 'README.md' -exec sed -i '' 's/敏感内容/替换内容/g' {} \;" \
  -- --all

# 3. 恢复暂存的更改
git stash pop

# 4. 强制推送到远程仓库（覆盖历史）
git push origin main --force</code></pre>
<h4>参数说明</h4>
<table>
<thead>
<tr>
<th>参数</th>
<th>说明</th>
</tr>
</thead>
<tbody>
<tr>
<td>&lt;code&gt;&#8211;force&lt;/code&gt;</td>
<td>强制执行，即使已有备份</td>
</tr>
<tr>
<td>&lt;code&gt;&#8211;tree-filter&lt;/code&gt;</td>
<td>对每个提交的文件树执行命令</td>
</tr>
<tr>
<td>&lt;code&gt;&#8211; &#8211;all&lt;/code&gt;</td>
<td>处理所有分支</td>
</tr>
<tr>
<td>&lt;code&gt;sed -i &#039;&#039;&lt;/code&gt;</td>
<td>macOS 下的原地替换（Linux 用 &lt;code&gt;sed -i&lt;/code&gt;）</td>
</tr>
</tbody>
</table>
<h3>方法二：使用 BFG Repo-Cleaner（推荐，更快）</h3>
<p>适用于删除大文件或敏感文件。</p>
<pre><code class="language-bash"># 安装 BFG
brew install bfg

# 删除某个文件的所有历史
bfg --delete-files 敏感文件.txt

# 或替换敏感文本
bfg --replace-text passwords.txt

# 清理并强制推送
git reflog expire --expire=now --all
git gc --prune=now --aggressive
git push origin main --force</code></pre>
<h3>方法三：使用 git filter-repo（官方推荐）</h3>
<pre><code class="language-bash"># 安装
brew install git-filter-repo

# 替换敏感内容
git filter-repo --replace-text &lt;(echo '敏感内容==&gt;替换内容')

# 重新添加远程并推送
git remote add origin https://github.com/user/repo.git
git push origin main --force</code></pre>
<h2>注意事项</h2>
<ol>
<li><strong>强制推送有风险</strong>：会覆盖远程历史，协作者需要重新克隆仓库</li>
<li><strong>轮换密钥</strong>：敏感信息一旦泄露，应立即轮换（如重新生成 API Key）</li>
<li><strong>GitHub 缓存</strong>：GitHub 可能会缓存提交，联系 GitHub 支持可请求清除</li>
<li><strong>本地备份</strong>：操作前建议备份仓库 &lt;code&gt;cp -r .git .git.backup&lt;/code&gt;</li>
</ol>
<h2>预防措施</h2>
<ul>
<li>使用 &lt;code&gt;.gitignore&lt;/code&gt; 忽略敏感文件</li>
<li>使用环境变量存储敏感配置</li>
<li>提交前检查 &lt;code&gt;git diff &#8211;staged&lt;/code&gt;</li>
<li>启用 GitHub 的 Secret Scanning 功能</li>
</ul>
<h2>总结</h2>
<ol>
<li>git stash &#8211; 暂存当前未提交的更改</li>
<li>git filter-branch &#8211;tree-filter &#8211; 遍历所有历史提交，用 sed 替换敏感内容</li>
<li>git stash pop &#8211; 恢复暂存的更改</li>
<li>git push &#8211;force &#8211; 强制推送覆盖远程历史</li>
</ol>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Mac 中刷新 DNS</title>
		<link>https://blog.yangyuanping.com/mac-%e4%b8%ad%e5%88%b7%e6%96%b0-dns/</link>
		
		<dc:creator><![CDATA[peny911]]></dc:creator>
		<pubDate>Wed, 26 Nov 2025 15:40:53 +0000</pubDate>
				<category><![CDATA[Linux Nibbles]]></category>
		<category><![CDATA[DNS]]></category>
		<category><![CDATA[Mac]]></category>
		<guid isPermaLink="false">https://blog.yangyuanping.com/?p=1039</guid>

					<description><![CDATA[在 Mac（macOS） 中刷新 DNS 缓存没有像 Windows 那样统一的 &#60;code&#62;ip [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>在 <strong>Mac（macOS）</strong> 中刷新 DNS 缓存没有像 Windows 那样统一的 &lt;code&gt;ipconfig /flushdns&lt;/code&gt;，而是<strong>按系统版本使用不同的 &lt;code&gt;dscacheutil&lt;/code&gt; + &lt;code&gt;killall mDNSResponder&lt;/code&gt; 组合命令</strong>。</p>
<hr />
<h2><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 一行通用万能命令（推荐直接用这个）</h2>
<p>在 <strong>终端（Terminal）</strong> 中执行：</p>
<pre><code class="language-bash">sudo dscacheutil -flushcache; sudo killall -HUP mDNSResponder</code></pre>
<p>输入你的 <strong>系统登录密码</strong>（不会显示），回车即可完成刷新。</p>
<blockquote>
<p>这个命令适用于：</p>
</blockquote>
<ul>
<li>macOS Ventura (13)</li>
<li>macOS Sonoma (14)</li>
<li>macOS Sequoia (15)</li>
<li>Monterey (12)</li>
<li>Big Sur (11)</li>
<li>Catalina (10.15)</li>
<li>Mojave (10.14)</li>
</ul>
<hr />
<h2><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4cc.png" alt="📌" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 各系统版本对应命令（备用参考）</h2>
<table>
<thead>
<tr>
<th>macOS 版本</th>
<th>刷新 DNS 命令</th>
</tr>
</thead>
<tbody>
<tr>
<td>10.10.4 及以后</td>
<td>&lt;code&gt;sudo dscacheutil -flushcache; sudo killall -HUP mDNSResponder&lt;/code&gt;</td>
</tr>
<tr>
<td>10.10 – 10.10.3</td>
<td>&lt;code&gt;sudo discoveryutil mdnsflushcache; sudo discoveryutil udnsflushcaches&lt;/code&gt;</td>
</tr>
<tr>
<td>10.7 – 10.9</td>
<td>&lt;code&gt;sudo killall -HUP mDNSResponder&lt;/code&gt;</td>
</tr>
<tr>
<td>10.5 – 10.6</td>
<td>&lt;code&gt;sudo dscacheutil -flushcache&lt;/code&gt;</td>
</tr>
</tbody>
</table>
<hr />
<h2><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 如何判断是否刷新成功？</h2>
<p>macOS 刷新 DNS <strong>默认是没有任何成功提示的</strong>，这是正常现象 <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /><br />
如果你想确认是否真的生效，可以：</p>
<pre><code class="language-bash">ping your-domain.com</code></pre>
<p>或：</p>
<pre><code class="language-bash">nslookup your-domain.com</code></pre>
<hr />
<h2><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 适合你的使用场景（比如你刚刚在折腾这些）</h2>
<p>你最近使用的场景包括：</p>
<ul>
<li><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 花生壳 / 动态域名解析</li>
<li><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 公网 IP + 远程桌面</li>
<li><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 路由器 DDNS 解析切换</li>
<li><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 域名刚刚改解析但访问不生效</li>
</ul>
<p><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f449.png" alt="👉" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <strong>这时候刷新 DNS 是“必须操作”之一，否则很容易一直命中旧 IP</strong>。</p>
<hr />
<h2><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 进阶：同时刷新 WiFi/网络缓存（更彻底）</h2>
<p>如果你遇到的是那种 <strong>“DNS 已改，但 Mac 仍然连不上”</strong> 的顽固情况，可以：</p>
<pre><code class="language-bash">sudo dscacheutil -flushcache
sudo killall -HUP mDNSResponder
sudo ifconfig en0 down
sudo ifconfig en0 up</code></pre>
<p>（&lt;code&gt;en0&lt;/code&gt; 是常见的 WiFi 网卡）</p>
<hr />
]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
