IIS 中使用 HttpPlatformHandler 模块部署 python web 项目时遇到 502.3 网关错误:
HTTP 错误 502.3 - Bad Gateway
There was a connection error while trying to route the request.
最可能的原因:
CGI 应用程序没有返回一组有效的 HTTP 错误。
由于父网关中出现错误,充当代理或网关的服务器无法处理该请求。
可尝试的操作:
使用 DebugDiag 排查 CGI 应用程序。
确定此错误是否由代理或网关引起。
详细错误信息:
模块 httpPlatformHandler
通知 ExecuteRequestHandler
处理程序 httpplatformhandler
错误代码 见下方表格
详细信息:
当 CGI 应用程序未返回一组有效的 HTTP 头,或者代理或网关无法将请求发送至父网关时,便会出现此错误。您可能需要获取一个网络跟踪,或者与代理服务器管理员联系(如果不是 CGI 的问题)。
错误代码 | 可能的错误原因 |
---|---|
0x8007053d | 未安装相关组件库,建议执行命令:pip install -r requirements.txt |
0x80070005 | 若显示配置错误“由于权限不足而无法读取配置文件”则是应用代码目录未配置相应用户的读取权限; 访问受限,请正确配置 IIS 中的网站凭据、应用程序池标识、项目目录“读取”、解释器目录“读取和执行”权限等 |
0x80072ee2 | 执行超时,一般发生在批量读写的时候 |


安装 PyPI(包/库/组件):
pip install 包名
如果安装失败,尝试用国内镜像
pip install 包名 -i https://pypi.tuna.tsinghua.edu.cn/simple
如果不想每次都加 -i 参数,可以更改全局配置
pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple
查看所有配置
pip config list
查看 python 文件路径
# Windows 或 Linux 通用 python -c "import sys; print(sys.executable)"
默认路径为:C:\Users\<user name>\AppData\Local\Programs\Python\Python<version>\python.exe
常用组件介绍
包名 | 介绍 |
---|---|
Flask | 一款基于 Python 的轻量级 Web 开发框架 |
Django | 一款基于 Python 的重量级 Web 开发框架 |
Pandas | 一个数据分析包,提供 Series、Time-Series、DataFrame、Panel、Panel4D、PanelND 等数据结构 |
更多

安装“腾讯手机管家”或其它支持按关键词设置黑名单的垃圾信息过滤工具
打开手机设置 - App - 信息 - 未知与过滤信息 - 选择“腾讯手机管家”
打开“腾讯手机管家”- 垃圾短信过滤 - 自定义短信拦截 - 黑名单 - 添加关键词
(每次添加一个词就确定,如果填写多个表示同一条短信中同时包含这些关键词)

在代码中添加“不跟踪”(No-Tracking)功能,以提高查询性能(避免实体状态跟踪)。
确保后续操作无需更新返回的实体(如没有 SaveChanges 操作)。
在条件(Where)、排序(OrderBy、OrderByDescending)、分页(Skip、Take)等之前添加 .AsNoTracking(),如:db.Table.AsNoTracking().Where(...).ToList()。
如果查询中包含导航属性,它们也会因主查询的不跟踪而保持不跟踪状态。
AsNoTracking() 适用于查询简单无嵌套关系,若查询包含 Include/ThenInclude,建议用 AsNoTrackingWithIdentityResolution() 代替,后者更适合处理树形结构或循环引用数据。
添加(Add/AddRange)、修改、删除(Remove/RemoveRange)等有 SaveChanges 操作的场景不能加 .AsNoTracking()。
查询时是否需要加 .AsNoTracking() 参考下表:
数据查询操作体系
├── 限定符 (Any, All) ✔️ 推荐
├── 聚合函数 (Count, Sum, Min, Max, Average) ❌ 不需要(但在分页逻辑中 Count 与 ToList 使用共同条件筛选时建议加)
├── 集合操作 (Distinct, Union) ⚠️ 推荐用于只读
├── 元素操作 (First, Single) ⚠️ 推荐用于只读
└── 即时执行操作 (ToList, ToArray, ToDictionary) ⚠️ 推荐用于只读

AsNoTracking 设置未追踪查询
var customers = dbContext.Customers.AsNoTracking().ToList();
这对于只读查询非常有用,因为它可以减少内存使用并提高性能,因为它不需要维护实体的更改跟踪信息。
ExecuteDelete 和 ExecuteUpdate 批量操作
context.Logs.Where(c => c.Time < new DateTime(2000, 1, 1)).ExecuteDelete();
从 EF Core 7 开始,ExecuteDelete 和 ExecuteUpdate 是官方原生支持的批量操作方法。直接操作数据库,不需要调用 SaveChanges():不加载实体到内存,减少内存消耗和网络往返。
若需要分页删除和大批量插入,或在高频、大规模场景,推荐使用 Zack.EFCore.Batch:
context.Logs.Where(c => c.Time < new DateTime(2000, 1, 1)).DeleteRangeAsync(batchSize: 1000);
考虑用 Union 代替 OR
// Where 后行数多时(如分页前)用 OR var q = db.dt_crm__contract.AsNoTracking(); q = q.Where(c => c.dt_crm__customer.SalesmanId == uid || myIns.Contains(c.IndustryId)); // 用于合并的 q1、q2 的行数少时用 Union var q1 = db.dt_crm__contract.AsNoTracking().Where(c => c.dt_crm__customer.SalesmanId == uid); var q2 = db.dt_crm__contract.AsNoTracking().Where(c => myIns.Contains(c.IndustryId)); var q = q1.Union(q2);
“ToDictionary + Count”之前先 Select
// 不推荐 var dic = q.GroupBy(c => c.Date) .ToDictionary(k => k.Key, v => v.Count()); // 推荐 var dic = q.GroupBy(c => c.Date) .Select(g => new { g.Key, Count = g.Count() }) .ToDictionary(k => k.Key, v => v.Count);

现象:
VS2022 的“管理 nuget 程序包”页面的“更新”和“已安装”选项卡无限循环加载刷新,状态栏一直循环显示“正在还原 NuGet 程序包”、“就绪”。点开来有很多“正在加载 IntelliSense 任务已成功完成”。我有很多解决方案和项目,只有其中一个出现上述情况。
解决方法:
点击“设置”,在“常规”页面点击“清除所有 NuGet 存储”。

临界区与 lock 关键字
核心作用:
通过将多线程访问串行化,保护共享资源或代码段。lock 关键字是 Monitor 类的语法糖,提供异常安全的临界区实现。
实现示例:
// 创建私有静态只读对象 // private static readonly object _lockObj = new object(); private static readonly System.Threading.Lock _locker = new(); // .NET 9+ 推荐使用 Lock 类型,避免传统 object 的性能损耗 public void ThreadSafeMethod() { lock (_lockObj) { // 临界区代码(每次仅一个线程可进入) } }
超时机制:
高并发场景可结合 Monitor.TryEnter 设置超时,避免无限等待:
if (Monitor.TryEnter(lockObject, TimeSpan.FromSeconds(1))) { try { /* 操作 */ } finally { Monitor.Exit(lockObject); } }
关键特性:
用户态锁(无内核切换开销)
自动调用Monitor.Enter和Monitor.Exit
必须使用专用私有对象作为锁标识
注意事项:
❌ 避免锁定this、Type实例或字符串(易引发死锁)
❌ 避免嵌套锁(需严格按顺序释放)
✅ 推荐readonly修饰锁对象
❌ lock 不适用于异步代码(async/await),需使用 SemaphoreSlim 实现异步锁
互斥锁(Mutex)
核心作用:
系统级内核锁,支持跨进程同步,但性能开销较高(用户态/内核态切换)。
实现示例:
using var mutex = new Mutex(false, "Global\\MyAppMutex"); try { // 等待锁(最大等待时间500ms) if (mutex.WaitOne(500)) { // 临界区代码 } } finally { if (mutex != null) { mutex.ReleaseMutex(); } }
关键特性:
支持跨应用程序域同步
线程终止时自动释放锁
支持命名互斥体(系统全局可见)
适用场景:
单实例应用程序控制
进程间共享文件访问
硬件设备独占访问
信号量(Semaphore)
核心作用:
通过许可计数器控制并发线程数,SemaphoreSlim为轻量级版本(用户态实现)。
实现对比:
类型 跨进程 性能 最大许可数 Semaphore ✔️ 低 系统限制 SemaphoreSlim ❌ 高 Int32.Max 代码示例:
// 创建初始3许可、最大5许可的信号量 var semaphore = new SemaphoreSlim(3, 5); semaphore.Wait(); // 获取许可 try { // 资源访问代码 } finally { semaphore.Release(); }
异步编程
private readonly SemaphoreSlim _asyncLock = new(1, 1); public async Task UpdateAsync() { await _asyncLock.WaitAsync(); try { /* 异步操作 */ } finally { _asyncLock.Release(); } }
典型应用:
数据库连接池(限制最大连接数)
API 请求限流
批量任务并发控制
事件(Event)
核心机制:
通过信号机制实现线程间通知,分为两种类型:
类型 信号重置方式 唤醒线程数 AutoResetEvent 自动 单个 ManualResetEvent 手动 所有 使用示例:
var autoEvent = new AutoResetEvent(false); // 等待线程 Task.Run(() => { autoEvent.WaitOne(); // 收到信号后执行 }); // 信号发送线程 autoEvent.Set(); // 唤醒一个等待线程
高级用法:
配合WaitHandle.WaitAll实现多事件等待
使用ManualResetEventSlim提升性能
读写锁(ReaderWriterLockSlim)
核心优势:
实现读写分离的并发策略,适合读多写少场景(如缓存系统)。
锁模式对比:
模式 并发性 升级支持 读模式(EnterReadLock) 多线程并发读 ❌ 写模式(EnterWriteLock) 独占访问 ❌ 可升级模式 单线程读→写 ✔️ 代码示例:
var rwLock = new ReaderWriterLockSlim(); // 读操作 rwLock.EnterReadLock(); try { // 只读访问 } finally { rwLock.ExitReadLock(); } // 写操作 rwLock.EnterWriteLock(); try { // 排他写入 } finally { rwLock.ExitWriteLock(); }
最佳实践:
优先使用ReaderWriterLockSlim(旧版有死锁风险)
避免长时间持有读锁(可能饿死写线程)
原子操作(Interlocked)
原理:
通过CPU指令实现无锁线程安全操作。
常用方法:
int counter = 0; Interlocked.Increment(ref counter); // 原子递增 Interlocked.Decrement(ref counter); // 原子递减 Interlocked.CompareExchange(ref value, newVal, oldVal); // CAS操作
适用场景:
简单计数器
标志位状态切换
无锁数据结构实现
自旋锁(SpinLock)
核心特点:
通过忙等待(busy-wait)避免上下文切换,适用极短临界区(<1微秒)。
实现示例:
private SpinLock _spinLock = new SpinLock(); public void CriticalOperation() { bool lockTaken = false; try { _spinLock.Enter(ref lockTaken); // 极短临界区代码 } finally { if (lockTaken) _spinLock.Exit(); } }
优化技巧:
单核CPU需调用Thread.SpinWait或Thread.Yield
配合SpinWait结构实现自适应等待
同步机制对比指南
机制 跨进程 开销级别 最佳适用场景 lock ❌ 低 通用临界区保护 Mutex ✔️ 高 进程间资源独占 Semaphore ✔️ 中 并发数限制(跨进程) SemaphoreSlim ❌ 低 并发数限制(进程内) ReaderWriterLockSlim ❌ 中 读多写少场景 SpinLock ❌ 极低 纳秒级临界区 Interlocked - 无锁 简单原子操作
选择原则:
优先考虑用户态锁(lock/SpinLock/SemaphoreSlim)
跨进程需求必须使用内核对象(Mutex/Semaphore)
读写比例超过10:1时考虑读写锁
自旋锁仅用于高频短操作(如链表指针修改)
通过以上结构化的分类和对比,开发者可以更精准地选择适合特定场景的线程同步方案。建议在实际使用中配合性能分析工具(如BenchmarkDotNet)进行量化验证。
💡 ASP.NET 的异步编程(async/await)本质是单进程内的线程调度,不算“跨进程”。每个 IIS 应用程序池对应一个独立的工作进程(w3wp.exe),不同用户访问同一应用程序池下的 ASP.NET 网站,两者的请求均由同一个 w3wp.exe 进程处理。可能跨进程的场景有:Web Garden 配置、多应用程序池部署等。
在 C# 中,除了常规锁机制(如 lock、Mutex、Semaphore 等),还有一些内置类型通过内部锁或无锁设计实现线程安全。以下是常见的几类:
线程安全集合(System.Collections.Concurrent)这些集合通过细粒度锁或无锁算法(如 CAS)实现线程安全,适合高并发场景。
ConcurrentDictionary:分段锁机制,将数据分片存储,每个分片独立加锁,减少锁竞争。
ConcurrentQueue / ConcurrentStack:基于原子操作(Interlocked)保证线程安全。
ConcurrentBag:每个线程维护本地存储,减少争用,适合频繁添加和移除的场景。
BlockingCollection:基于 ConcurrentQueue 和信号量(SemaphoreSlim)实现生产-消费者模式,支持阻塞和超时。
不可变集合(System.Collections.Immutable) 通过数据不可变性实现线程安全(无需锁),每次修改返回新对象。
Lazy 的线程安全初始化(Lazy<T>) 通过锁或 Interlocked 确保延迟初始化的线程安全。
通道(System.Threading.Channels)用于异步生产-消费者模型,内部通过锁和信号量管理容量限制。
内存缓存(System.Runtime.Caching.MemoryCache)内部使用锁保护共享状态,确保线程安全。
原子操作类型(Interlocked 类、Volatile 关键字、Unsafe 类)通过 CPU 指令实现无锁线程安全。
其他同步工具(Barrier、CountdownEvent)虽然不是严格意义上的锁,但用于协调线程。

字段 | MySQL 中的类型和精度 | MySQL 中占用字节 | 原因说明 |
股票价格 | DECIMAL(10,2) | 5 | 股票价格四舍五入保留两位小数,避免浮点型精度丢失。 即使最贵的股票价格并没有超过 9999.99 元,但考虑到复权价和扩展性,建议用更大的类型。 |
基金价格 | 基金价格四舍五入保留三位小数,避免浮点型精度丢失。 | ||
精确的成交金额(元)、成交量(手) | BIGINT UNSIGNED | 8 | 取值范围 0 到 1844,6744,0737,0955,1615(即一千多个亿亿)。 2024年A股总成交金额为257万亿元。 |
不精确的成交金额、成交量 | float | 4 | 取值范围足够大,有效数字约为6-7位。 |
交易日 | DATE | 3 | 包括年、月、日 |
交易时间 | DATETIME | 8 | 精确到分钟 |
6位股票代码 | CHAR(6) | 6 | 6个半角字符占6个字节 |
股票名称 | VARCHAR(10) | utf-8 的一个汉字占3个字节 |
