- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我在学习 C 的同时正在编写 find
的克隆。在实现 -ls
选项时,我偶然发现了一个问题,即 getpwuid_r
和 getgrgid_r
调用真的很慢,同样适用于 getpwuid
和 getgrgid
。我需要它们根据 stat.h
提供的 ID 显示用户/组名。
例如,列出整个文件系统会慢 3 倍:
# measurements were made 3 times and the fastest run was recorded
# with getgrgid_r
time ./myfind / -ls > list.txt
real 0m4.618s
user 0m1.848s
sys 0m2.744s
# getgrgid_r replaced with 'return "user";'
time ./myfind / -ls > list.txt
real 0m1.437s
user 0m0.572s
sys 0m0.832s
我想知道GNU find 是如何保持这么好的速度的。我看过 sources , 但如果没有特殊类型、宏等,它们就不太容易理解和应用:
time find / -ls > list.txt
real 0m1.544s
user 0m0.884s
sys 0m0.648s
我考虑过在数据结构中缓存 uid - username
和 gid - groupname
对。这是不是一个好主意?您将如何实现?
你可以找到我的完整代码here .
更新:
solution正是我要找的:
time ./myfind / -ls > list.txt
real 0m1.480s
user 0m0.696s
sys 0m0.736s
这里是一个基于getgrgid
的版本(如果你不需要线程安全):
char *do_get_group(struct stat attr) {
struct group *grp;
static unsigned int cache_gid = UINT_MAX;
static char *cache_gr_name = NULL;
/* skip getgrgid if we have the record in cache */
if (cache_gid == attr.st_gid) {
return cache_gr_name;
}
/* clear the cache */
cache_gid = UINT_MAX;
grp = getgrgid(attr.st_gid);
if (!grp) {
/*
* the group is not found or getgrgid failed,
* return the gid as a string then;
* an unsigned int needs 10 chars
*/
char group[11];
if (snprintf(group, 11, "%u", attr.st_gid) < 0) {
fprintf(stderr, "%s: snprintf(): %s\n", program, strerror(errno));
return "";
}
return group;
}
cache_gid = grp->gr_gid;
cache_gr_name = grp->gr_name;
return grp->gr_name;
}
getpwuid
:
char *do_get_user(struct stat attr) {
struct passwd *pwd;
static unsigned int cache_uid = UINT_MAX;
static char *cache_pw_name = NULL;
/* skip getpwuid if we have the record in cache */
if (cache_uid == attr.st_uid) {
return cache_pw_name;
}
/* clear the cache */
cache_uid = UINT_MAX;
pwd = getpwuid(attr.st_uid);
if (!pwd) {
/*
* the user is not found or getpwuid failed,
* return the uid as a string then;
* an unsigned int needs 10 chars
*/
char user[11];
if (snprintf(user, 11, "%u", attr.st_uid) < 0) {
fprintf(stderr, "%s: snprintf(): %s\n", program, strerror(errno));
return "";
}
return user;
}
cache_uid = pwd->pw_uid;
cache_pw_name = pwd->pw_name;
return pwd->pw_name;
}
更新 2:
将 long
更改为 unsigned int
。
更新 3:
添加了缓存清除。这是绝对必要的,因为pwd->pw_name
可能指向一个静态区域。 getpwuid
可以在失败时或仅在程序中的其他地方执行时覆盖其内容。
同时删除了 strdup
。由于 getgrgid
和 getpwuid
的输出 should not be freed ,我们的包装函数不需要 free
。
最佳答案
时间确实表明对这些功能的强烈怀疑。
查看您的函数 do_get_group
,存在一些问题:
你使用 sysconf(_SC_GETPW_R_SIZE_MAX);
每次调用 do_get_group
和 do_get_user
,一定要缓存它,它不会改变在你的程序的生命周期中,但你不会有太多收获。
您使用 attr.st_uid
而不是 attr.st_gid
,这可能会导致许多文件的查找失败,可能会破坏缓存机制(如果有) .先修复这个,这是一个错误!
您返回的值不应由调用者传递给 free()
,例如 grp->gr_name
和 ""
。你应该总是分配你返回的字符串。 do_get_user()
中可能存在同样的问题。
这是用一次性缓存替换 do_get_group
的方法。看看这是否提高了性能:
/*
* @brief returns the groupname or gid, if group not present on the system
*
* @param attr the entry attributes from lstat
*
* @returns the groupname if getgrgid() worked, otherwise gid, as a string
*/
char *do_get_group(struct stat attr) {
char *group;
struct group grp;
struct group *result;
static size_t length = 0;
static char *buffer = NULL;
static gid_t cache_gid = -1;
static char *cache_gr_name = NULL;
if (!length) {
/* only allocate the buffer once */
long sysconf_length = sysconf(_SC_GETPW_R_SIZE_MAX);
if (sysconf_length == -1) {
sysconf_length = 16384;
}
length = (size_t)sysconf_length;
buffer = calloc(length, 1);
}
if (!buffer) {
fprintf(stderr, "%s: malloc(): %s\n", program, strerror(errno));
return strdup("");
}
/* check the cache */
if (cache_gid == attr.st_gid) {
return strdup(cache_gr_name);
}
/* empty the cache */
cache_gid = -1;
free(cache_gr_name);
cache_gr_name = NULL;
if (getgrgid_r(attr.st_gid, &grp, buffer, length, &result) != 0) {
fprintf(stderr, "%s: getpwuid_r(): %s\n", program, strerror(errno));
return strdup("");
}
if (result) {
group = grp.gr_name;
} else {
group = buffer;
if (snprintf(group, length, "%ld", (long)attr.st_gid) < 0) {
fprintf(stderr, "%s: snprintf(): %s\n", program, strerror(errno));
return strdup("");
}
}
/* load the cache */
cache_gid = attr.st_gid;
cache_gr_name = strdup(group);
return strdup(group);
}
关于c - getpwuid_r 和 getgrgid_r 很慢,如何缓存它们?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35821628/
我在学习 C 的同时正在编写 find 的克隆。在实现 -ls 选项时,我偶然发现了一个问题,即 getpwuid_r 和 getgrgid_r 调用真的很慢,同样适用于 getpwuid 和 get
我是一名优秀的程序员,十分优秀!