第13章 - 性能优化与最佳实践
第13章 - 性能优化与最佳实践
13.1 性能优化原则
13.1.1 性能瓶颈分析
LibreDWG应用的常见性能瓶颈:
| 操作 | 时间复杂度 | 优化方向 |
|---|---|---|
| 文件读取 | O(n) | 增量读取、内存映射 |
| 对象遍历 | O(n) | 索引、过滤 |
| 句柄解析 | O(log n) | 缓存 |
| 格式转换 | O(n) | 并行处理 |
| 内存分配 | O(1) | 预分配、池化 |
13.1.2 性能测量
#include <stdio.h>
#include <time.h>
#include <dwg.h>
// 简单计时器
typedef struct {
clock_t start;
const char *name;
} Timer;
void timer_start(Timer *t, const char *name)
{
t->name = name;
t->start = clock();
}
void timer_stop(Timer *t)
{
clock_t end = clock();
double elapsed = (double)(end - t->start) / CLOCKS_PER_SEC;
printf("%s: %.3f 秒\n", t->name, elapsed);
}
// 使用示例
void measure_performance(const char *filename)
{
Timer t;
Dwg_Data dwg;
timer_start(&t, "文件读取");
memset(&dwg, 0, sizeof(Dwg_Data));
int error = dwg_read_file(filename, &dwg);
timer_stop(&t);
if (error >= DWG_ERR_CRITICAL) {
printf("读取失败\n");
return;
}
timer_start(&t, "对象遍历");
int count = 0;
for (BITCODE_BL i = 0; i < dwg.num_objects; i++) {
Dwg_Object *obj = &dwg.object[i];
if (obj->fixedtype == DWG_TYPE_LINE) {
count++;
}
}
timer_stop(&t);
printf("直线数量: %d\n", count);
timer_start(&t, "内存释放");
dwg_free(&dwg);
timer_stop(&t);
}
13.2 读取优化
13.2.1 选择性读取
#include <dwg.h>
// 只读取需要的对象类型
void read_lines_only(const char *filename)
{
Dwg_Data dwg;
int error;
memset(&dwg, 0, sizeof(Dwg_Data));
error = dwg_read_file(filename, &dwg);
if (error >= DWG_ERR_CRITICAL) return;
// 直接定位LINE对象
for (BITCODE_BL i = 0; i < dwg.num_objects; i++) {
Dwg_Object *obj = &dwg.object[i];
// 跳过非实体
if (obj->supertype != DWG_SUPERTYPE_ENTITY) continue;
// 只处理LINE
if (obj->fixedtype != DWG_TYPE_LINE) continue;
Dwg_Entity_LINE *line = obj->tio.entity->tio.LINE;
// 处理直线...
}
dwg_free(&dwg);
}
13.2.2 延迟解析引用
#include <dwg.h>
// 延迟解析对象引用
void lazy_reference_resolution(Dwg_Data *dwg)
{
// 不立即解析所有引用
// 只在需要时解析
for (BITCODE_BL i = 0; i < dwg->num_objects; i++) {
Dwg_Object *obj = &dwg->object[i];
if (obj->supertype != DWG_SUPERTYPE_ENTITY) continue;
Dwg_Object_Entity *ent = obj->tio.entity;
// 只有需要图层名时才解析
// if (need_layer_name) {
// resolve_layer_ref(ent->layer);
// }
}
}
13.2.3 内存映射读取
对于大文件,可以考虑使用内存映射:
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <dwg.h>
// 内存映射读取(Linux)
int read_dwg_mmap(const char *filename, Dwg_Data *dwg)
{
int fd = open(filename, O_RDONLY);
if (fd == -1) return -1;
struct stat sb;
if (fstat(fd, &sb) == -1) {
close(fd);
return -1;
}
void *data = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
if (data == MAP_FAILED) {
close(fd);
return -1;
}
// 使用内存数据
// 注意:LibreDWG主要使用文件API,需要适配
munmap(data, sb.st_size);
close(fd);
return 0;
}
13.3 遍历优化
13.3.1 建立类型索引
#include <dwg.h>
#include <stdlib.h>
// 对象类型索引
typedef struct {
BITCODE_BL *indices;
BITCODE_BL count;
BITCODE_BL capacity;
} TypeIndex;
typedef struct {
TypeIndex lines;
TypeIndex circles;
TypeIndex texts;
TypeIndex layers;
} ObjectIndex;
// 初始化索引
void init_type_index(TypeIndex *idx)
{
idx->count = 0;
idx->capacity = 1000;
idx->indices = malloc(idx->capacity * sizeof(BITCODE_BL));
}
// 添加到索引
void add_to_index(TypeIndex *idx, BITCODE_BL index)
{
if (idx->count >= idx->capacity) {
idx->capacity *= 2;
idx->indices = realloc(idx->indices,
idx->capacity * sizeof(BITCODE_BL));
}
idx->indices[idx->count++] = index;
}
// 建立索引
void build_object_index(Dwg_Data *dwg, ObjectIndex *idx)
{
init_type_index(&idx->lines);
init_type_index(&idx->circles);
init_type_index(&idx->texts);
init_type_index(&idx->layers);
for (BITCODE_BL i = 0; i < dwg->num_objects; i++) {
Dwg_Object *obj = &dwg->object[i];
switch (obj->fixedtype) {
case DWG_TYPE_LINE:
add_to_index(&idx->lines, i);
break;
case DWG_TYPE_CIRCLE:
add_to_index(&idx->circles, i);
break;
case DWG_TYPE_TEXT:
case DWG_TYPE_MTEXT:
add_to_index(&idx->texts, i);
break;
case DWG_TYPE_LAYER:
add_to_index(&idx->layers, i);
break;
}
}
}
// 使用索引遍历
void iterate_lines_fast(Dwg_Data *dwg, ObjectIndex *idx)
{
for (BITCODE_BL i = 0; i < idx->lines.count; i++) {
BITCODE_BL obj_idx = idx->lines.indices[i];
Dwg_Object *obj = &dwg->object[obj_idx];
Dwg_Entity_LINE *line = obj->tio.entity->tio.LINE;
// 处理直线...
}
}
// 释放索引
void free_object_index(ObjectIndex *idx)
{
free(idx->lines.indices);
free(idx->circles.indices);
free(idx->texts.indices);
free(idx->layers.indices);
}
13.3.2 空间索引
对于空间查询,可以使用四叉树或R树:
#include <dwg.h>
#include <stdlib.h>
// 简单的边界框
typedef struct {
double min_x, min_y, max_x, max_y;
} BBox;
// 四叉树节点
typedef struct QuadNode {
BBox bounds;
BITCODE_BL *objects; // 对象索引数组
BITCODE_BL obj_count;
struct QuadNode *children[4]; // NW, NE, SW, SE
} QuadNode;
// 创建节点
QuadNode* create_node(double min_x, double min_y,
double max_x, double max_y)
{
QuadNode *node = calloc(1, sizeof(QuadNode));
node->bounds.min_x = min_x;
node->bounds.min_y = min_y;
node->bounds.max_x = max_x;
node->bounds.max_y = max_y;
return node;
}
// 插入对象
void quad_insert(QuadNode *node, BITCODE_BL obj_idx,
double x, double y, int depth)
{
// 简化实现
// 实际应用需要更完整的四叉树实现
}
// 范围查询
void quad_query(QuadNode *node, BBox *query,
BITCODE_BL *results, BITCODE_BL *count)
{
// 检查是否相交
// 递归查询子节点
}
13.4 内存优化
13.4.1 预分配内存
#include <dwg.h>
#include <stdlib.h>
// 预分配结果数组
typedef struct {
void **items;
size_t count;
size_t capacity;
size_t item_size;
} PreallocArray;
void preallocarray_init(PreallocArray *arr, size_t initial_capacity,
size_t item_size)
{
arr->capacity = initial_capacity;
arr->count = 0;
arr->item_size = item_size;
arr->items = malloc(initial_capacity * item_size);
}
void* preallocarray_add(PreallocArray *arr)
{
if (arr->count >= arr->capacity) {
arr->capacity *= 2;
arr->items = realloc(arr->items, arr->capacity * arr->item_size);
}
return (char*)arr->items + (arr->count++ * arr->item_size);
}
void preallocarray_free(PreallocArray *arr)
{
free(arr->items);
arr->items = NULL;
arr->count = 0;
arr->capacity = 0;
}
13.4.2 对象池
#include <stdlib.h>
// 简单对象池
typedef struct {
void *memory;
size_t block_size;
size_t num_blocks;
size_t next_free;
size_t *free_list;
} ObjectPool;
void pool_init(ObjectPool *pool, size_t block_size, size_t num_blocks)
{
pool->block_size = block_size;
pool->num_blocks = num_blocks;
pool->memory = malloc(block_size * num_blocks);
pool->free_list = malloc(num_blocks * sizeof(size_t));
pool->next_free = 0;
// 初始化空闲链表
for (size_t i = 0; i < num_blocks - 1; i++) {
pool->free_list[i] = i + 1;
}
pool->free_list[num_blocks - 1] = (size_t)-1;
}
void* pool_alloc(ObjectPool *pool)
{
if (pool->next_free == (size_t)-1) {
return NULL; // 池已满
}
size_t idx = pool->next_free;
pool->next_free = pool->free_list[idx];
return (char*)pool->memory + idx * pool->block_size;
}
void pool_free(ObjectPool *pool, void *ptr)
{
size_t idx = ((char*)ptr - (char*)pool->memory) / pool->block_size;
pool->free_list[idx] = pool->next_free;
pool->next_free = idx;
}
void pool_destroy(ObjectPool *pool)
{
free(pool->memory);
free(pool->free_list);
}
13.4.3 及时释放
#include <dwg.h>
// 分阶段处理,及时释放
void process_large_file(const char *filename)
{
Dwg_Data dwg;
// 第一阶段:提取图层信息
memset(&dwg, 0, sizeof(Dwg_Data));
dwg_read_file(filename, &dwg);
// 处理图层...
// 保存必要信息后释放
dwg_free(&dwg);
// 第二阶段:提取实体信息
memset(&dwg, 0, sizeof(Dwg_Data));
dwg_read_file(filename, &dwg);
// 处理实体...
dwg_free(&dwg);
}
13.5 并行处理
13.5.1 多文件并行
#include <stdio.h>
#include <pthread.h>
#include <dwg.h>
typedef struct {
char *filename;
int result;
} ProcessTask;
void* process_file_thread(void *arg)
{
ProcessTask *task = (ProcessTask*)arg;
Dwg_Data dwg;
memset(&dwg, 0, sizeof(Dwg_Data));
int error = dwg_read_file(task->filename, &dwg);
if (error < DWG_ERR_CRITICAL) {
// 处理文件
task->result = dwg.num_objects;
dwg_free(&dwg);
} else {
task->result = -1;
}
return NULL;
}
void batch_process_parallel(char **files, int file_count, int max_threads)
{
pthread_t *threads = malloc(max_threads * sizeof(pthread_t));
ProcessTask *tasks = malloc(file_count * sizeof(ProcessTask));
int active = 0;
int completed = 0;
int started = 0;
while (completed < file_count) {
// 启动新线程
while (active < max_threads && started < file_count) {
tasks[started].filename = files[started];
pthread_create(&threads[started % max_threads], NULL,
process_file_thread, &tasks[started]);
started++;
active++;
}
// 等待完成
if (active > 0) {
pthread_join(threads[completed % max_threads], NULL);
printf("完成: %s, 对象数: %d\n",
tasks[completed].filename, tasks[completed].result);
completed++;
active--;
}
}
free(threads);
free(tasks);
}
13.5.2 Python并行处理
#!/usr/bin/env python3
"""并行处理DWG文件"""
import libredwg
from concurrent.futures import ProcessPoolExecutor, as_completed
from pathlib import Path
import multiprocessing
def process_single_file(filepath):
"""处理单个文件"""
try:
dwg = libredwg.Dwg_Data()
error = libredwg.dwg_read_file(str(filepath), dwg)
if error >= libredwg.DWG_ERR_CRITICAL:
return {'file': str(filepath), 'error': error}
result = {
'file': str(filepath),
'objects': dwg.num_objects,
'error': None
}
libredwg.dwg_free(dwg)
return result
except Exception as e:
return {'file': str(filepath), 'error': str(e)}
def batch_process_parallel(directory, max_workers=None):
"""并行批量处理"""
if max_workers is None:
max_workers = multiprocessing.cpu_count()
files = list(Path(directory).glob('*.dwg'))
results = []
with ProcessPoolExecutor(max_workers=max_workers) as executor:
futures = {executor.submit(process_single_file, f): f for f in files}
for future in as_completed(futures):
result = future.result()
results.append(result)
print(f"完成: {result['file']}")
return results
if __name__ == '__main__':
import sys
results = batch_process_parallel(sys.argv[1] if len(sys.argv) > 1 else '.')
success = sum(1 for r in results if r['error'] is None)
print(f"\n处理完成: {success}/{len(results)} 成功")
13.6 最佳实践
13.6.1 代码组织
project/
├── src/
│ ├── dwg_reader.c # DWG读取封装
│ ├── dwg_writer.c # DWG写入封装
│ ├── entity_utils.c # 实体工具函数
│ ├── layer_utils.c # 图层工具函数
│ └── main.c # 主程序
├── include/
│ ├── dwg_reader.h
│ ├── dwg_writer.h
│ └── utils.h
├── tests/
│ └── test_*.c
├── CMakeLists.txt
└── README.md
13.6.2 错误处理模式
#include <dwg.h>
#include <stdio.h>
// 定义错误处理宏
#define CHECK_DWG_ERROR(err, msg) do { \
if ((err) >= DWG_ERR_CRITICAL) { \
fprintf(stderr, "错误: %s (0x%x)\n", msg, err); \
return -1; \
} \
if (err) { \
fprintf(stderr, "警告: %s (0x%x)\n", msg, err); \
} \
} while(0)
// 使用示例
int safe_read_dwg(const char *filename, Dwg_Data *dwg)
{
int error;
memset(dwg, 0, sizeof(Dwg_Data));
error = dwg_read_file(filename, dwg);
CHECK_DWG_ERROR(error, "读取文件");
return 0;
}
13.6.3 资源管理模式
#include <dwg.h>
#include <stdlib.h>
// RAII风格的资源管理
typedef struct {
Dwg_Data dwg;
int loaded;
} DwgHandle;
int dwg_handle_open(DwgHandle *handle, const char *filename)
{
memset(&handle->dwg, 0, sizeof(Dwg_Data));
int error = dwg_read_file(filename, &handle->dwg);
if (error >= DWG_ERR_CRITICAL) {
handle->loaded = 0;
return -1;
}
handle->loaded = 1;
return 0;
}
void dwg_handle_close(DwgHandle *handle)
{
if (handle->loaded) {
dwg_free(&handle->dwg);
handle->loaded = 0;
}
}
// 使用示例
void process_with_handle(const char *filename)
{
DwgHandle handle;
if (dwg_handle_open(&handle, filename) != 0) {
return;
}
// 使用 handle.dwg ...
dwg_handle_close(&handle);
}
13.6.4 配置管理
#include <dwg.h>
// 应用配置
typedef struct {
int verbose;
int trace_level;
int resolve_refs;
Dwg_Version_Type output_version;
double precision;
} AppConfig;
// 默认配置
void config_default(AppConfig *cfg)
{
cfg->verbose = 0;
cfg->trace_level = 0;
cfg->resolve_refs = 1;
cfg->output_version = R_2000;
cfg->precision = 6;
}
// 应用配置
void apply_config(Dwg_Data *dwg, AppConfig *cfg)
{
if (cfg->trace_level > 0) {
// 设置跟踪级别
char trace_str[8];
snprintf(trace_str, sizeof(trace_str), "%d", cfg->trace_level);
setenv("LIBREDWG_TRACE", trace_str, 1);
}
if (cfg->resolve_refs && dwg->dirty_refs) {
dwg_resolve_objectrefs_silent(dwg);
}
}
13.7 本章小结
本章介绍了LibreDWG应用的性能优化和最佳实践:
- 性能测量:使用计时器分析瓶颈
- 读取优化:选择性读取、延迟解析、内存映射
- 遍历优化:类型索引、空间索引
- 内存优化:预分配、对象池、及时释放
- 并行处理:多线程、多进程批量处理
- 最佳实践:代码组织、错误处理、资源管理
下一章预告:第14章 - 常见问题与故障排除 - 解决LibreDWG使用中的常见问题。

浙公网安备 33010602011771号