ext4 buddy块分配算法源码剖析

2023-11-17

概述
ext4 buddy块分配算法的函数是ext4_mb_regular_allocator,阅读本文之前需要先看下ext4 mballoc之buddy算法_nginux的博客-CSDN博客
ext4_mb_regular_allocator源码

static noinline_for_stack int
ext4_mb_regular_allocator(struct ext4_allocation_context *ac)
{
	ext4_group_t prefetch_grp = 0, ngroups, group, i;
	int cr = -1;
	int err = 0, first_err = 0;
	unsigned int nr = 0, prefetch_ios = 0;
	struct ext4_sb_info *sbi;
	struct super_block *sb;
	struct ext4_buddy e4b;
	int lost;

	sb = ac->ac_sb;
	sbi = EXT4_SB(sb);
	ngroups = ext4_get_groups_count(sb);
	/* non-extent files are limited to low blocks/groups */
	if (!(ext4_test_inode_flag(ac->ac_inode, EXT4_INODE_EXTENTS)))
		ngroups = sbi->s_blockfile_groups;

	BUG_ON(ac->ac_status == AC_STATUS_FOUND);

	/* first, try the goal */
    //首先尝试从goal分配物理块,如果分配到goto out返回
	err = ext4_mb_find_by_goal(ac, &e4b);
	if (err || ac->ac_status == AC_STATUS_FOUND)
		goto out;

	if (unlikely(ac->ac_flags & EXT4_MB_HINT_GOAL_ONLY))
		goto out;

	/*
	 * ac->ac_2order is set only if the fe_len is a power of 2
	 * if ac->ac_2order is set we also set criteria to 0 so that we
	 * try exact allocation using buddy.
	 */
	i = fls(ac->ac_g_ex.fe_len);
	ac->ac_2order = 0;
	/*
	 * We search using buddy data only if the order of the request
	 * is greater than equal to the sbi_s_mb_order2_reqs
	 * You can tune it via /sys/fs/ext4/<partition>/mb_order2_req
	 * We also support searching for power-of-two requests only for
	 * requests upto maximum buddy size we have constructed.
	 */
	if (i >= sbi->s_mb_order2_reqs && i <= sb->s_blocksize_bits + 2) {
		/*
		 * This should tell if fe_len is exactly power of 2
		 */
        //申请分配的数量刚好是2的N次方,比如申请1024个block,那么ac->ac_2order = 10
		if ((ac->ac_g_ex.fe_len & (~(1 << (i - 1)))) == 0)
			ac->ac_2order = array_index_nospec(i - 1,
							   sb->s_blocksize_bits + 2);
	}

	/* if stream allocation is enabled, use global goal */
    //由于goal目标物理块无法申请到空间,那么从文件系统上次分配的地方开始分配
	if (ac->ac_flags & EXT4_MB_STREAM_ALLOC) {
		/* TBD: may be hot point */
		spin_lock(&sbi->s_md_lock);
		ac->ac_g_ex.fe_group = sbi->s_mb_last_group;
		ac->ac_g_ex.fe_start = sbi->s_mb_last_start;
		spin_unlock(&sbi->s_md_lock);
	}

	/* Let's just scan groups to find more-less suitable blocks */
	cr = ac->ac_2order ? 0 : 1;
    //申请有个严苛程度的概念,如果是2^N方申请量,那么就用cr=0代表精确分配请求数量的物理物理块
	/*
	 * cr == 0 try to get exact allocation,
	 * cr == 3  try to get anything
	 */
repeat:
	for (; cr < 4 && ac->ac_status == AC_STATUS_CONTINUE; cr++) {
		ac->ac_criteria = cr;
		/*
		 * searching for the right group start
		 * from the goal value specified
		 */
		group = ac->ac_g_ex.fe_group;
		prefetch_grp = group;

		for (i = 0; i < ngroups; group++, i++) {
			int ret = 0;
			cond_resched();
			/*
			 * Artificially restricted ngroups for non-extent
			 * files makes group > ngroups possible on first loop.
			 */
			if (group >= ngroups)
				group = 0;

	        ...

			/* This now checks without needing the buddy page */
			ret = ext4_mb_good_group_nolock(ac, group, cr);
			if (ret <= 0) {
				if (!first_err)
					first_err = ret;
				continue;
			}

			err = ext4_mb_load_buddy(sb, group, &e4b);
			if (err)
				goto out;

			ext4_lock_group(sb, group);

			/*
			 * We need to check again after locking the
			 * block group
			 */
			ret = ext4_mb_good_group(ac, group, cr);
			if (ret == 0) {
				ext4_unlock_group(sb, group);
				ext4_mb_unload_buddy(&e4b);
				continue;
			}

            //到这里说明已经找到good group来申请空间
			ac->ac_groups_scanned++;
			if (cr == 0)
                //申请的block数量正好是2的N次方
				ext4_mb_simple_scan_group(ac, &e4b);
			else if (cr == 1 && sbi->s_stripe &&
					!(ac->ac_g_ex.fe_len % sbi->s_stripe))
                //要分配的长度是stripe的整数倍,这是对raid的优化
				ext4_mb_scan_aligned(ac, &e4b);
			else
                //遍历block group内的所有空闲空间段,然后找出最合适的空闲空间段
				ext4_mb_complex_scan_group(ac, &e4b);

			ext4_unlock_group(sb, group);
			ext4_mb_unload_buddy(&e4b);

			if (ac->ac_status != AC_STATUS_CONTINUE)
				break;
		}
	}

    //走到这里说明最终也没有分配到空间
	if (ac->ac_b_ex.fe_len > 0 && ac->ac_status != AC_STATUS_FOUND &&
	    !(ac->ac_flags & EXT4_MB_HINT_FIRST)) {
		/*
		 * We've been searching too long. Let's try to allocate
		 * the best chunk we've found so far
		 */
        // 有空闲空间就行
		ext4_mb_try_best_found(ac, &e4b);

        //再尝试遍历一次所有的block group有空闲空间就行
		if (ac->ac_status != AC_STATUS_FOUND) {
			/*
			 * Someone more lucky has already allocated it.
			 * The only thing we can do is just take first
			 * found block(s)
			 */
			lost = atomic_inc_return(&sbi->s_mb_lost_chunks);
			mb_debug(sb, "lost chunk, group: %u, start: %d, len: %d, lost: %d\n",
				 ac->ac_b_ex.fe_group, ac->ac_b_ex.fe_start,
				 ac->ac_b_ex.fe_len, lost);

			ac->ac_b_ex.fe_group = 0;
			ac->ac_b_ex.fe_start = 0;
			ac->ac_b_ex.fe_len = 0;
			ac->ac_status = AC_STATUS_CONTINUE;
			ac->ac_flags |= EXT4_MB_HINT_FIRST;
			cr = 3;
			goto repeat;
		}
	}
out:
	if (!err && ac->ac_status != AC_STATUS_FOUND && first_err)
		err = first_err;

	mb_debug(sb, "Best len %d, origin len %d, ac_status %u, ac_flags 0x%x, cr %d ret %d\n",
		 ac->ac_b_ex.fe_len, ac->ac_o_ex.fe_len, ac->ac_status,
		 ac->ac_flags, cr, err);

	if (nr)
		ext4_mb_prefetch_fini(sb, prefetch_grp, nr);

	return err;
}
ext4_mb_find_by_goal

static noinline_for_stack
int ext4_mb_find_by_goal(struct ext4_allocation_context *ac,
				struct ext4_buddy *e4b)
{
	ext4_group_t group = ac->ac_g_ex.fe_group;
	int max;
	int err;
	struct ext4_sb_info *sbi = EXT4_SB(ac->ac_sb);
	struct ext4_group_info *grp = ext4_get_group_info(ac->ac_sb, group);
	struct ext4_free_extent ex;

	if (!(ac->ac_flags & EXT4_MB_HINT_TRY_GOAL))
		return 0;
	if (grp->bb_free == 0)
		return 0;

	err = ext4_mb_load_buddy(ac->ac_sb, group, e4b);
	if (err)
		return err;

	if (unlikely(EXT4_MB_GRP_BBITMAP_CORRUPT(e4b->bd_info))) {
		ext4_mb_unload_buddy(e4b);
		return 0;
	}

	ext4_lock_group(ac->ac_sb, group);
    //根据buddy bitmap,查找已ac_g_ex的起始物理块号fe_start开始的空闲区域长度,最少
    //要>=fe_len,当然也有可能不存在这么大的连续空闲区间。
	max = mb_find_extent(e4b, ac->ac_g_ex.fe_start,
			     ac->ac_g_ex.fe_len, &ex);
	ex.fe_logical = 0xDEADFA11; /* debug value */

    //这个分支是ext4文件系统对raid的优化,当分配的起始地址和长度都对齐到stripe时才分配
	if (max >= ac->ac_g_ex.fe_len && ac->ac_g_ex.fe_len == sbi->s_stripe) {
		ext4_fsblk_t start;

		start = ext4_group_first_block_no(ac->ac_sb, e4b->bd_group) +
			ex.fe_start;
		/* use do_div to get remainder (would be 64-bit modulo) */
		if (do_div(start, sbi->s_stripe) == 0) {
			ac->ac_found++;
			ac->ac_b_ex = ex;
			ext4_mb_use_best_found(ac, e4b);
		}
	} else if (max >= ac->ac_g_ex.fe_len) {
        //分配成功
		BUG_ON(ex.fe_len <= 0);
		BUG_ON(ex.fe_group != ac->ac_g_ex.fe_group);
		BUG_ON(ex.fe_start != ac->ac_g_ex.fe_start);
		ac->ac_found++;
		ac->ac_b_ex = ex;n
		ext4_mb_use_best_found(ac, e4b);
	} else if (max > 0 && (ac->ac_flags & EXT4_MB_HINT_MERGE)) {
		/* Sometimes, caller may want to merge even small
		 * number of blocks to an existing extent */
		BUG_ON(ex.fe_len <= 0);
		BUG_ON(ex.fe_group != ac->ac_g_ex.fe_group);
		BUG_ON(ex.fe_start != ac->ac_g_ex.fe_start);
		ac->ac_found++;
		ac->ac_b_ex = ex;
		ext4_mb_use_best_found(ac, e4b);
	}
	ext4_unlock_group(ac->ac_sb, group);
	ext4_mb_unload_buddy(e4b);

	return 0;
}
mb_find_extent源码

static int mb_find_extent(struct ext4_buddy *e4b, int block,
				int needed, struct ext4_free_extent *ex)
{
	int next = block;
	int max, order;
	void *buddy;

	assert_spin_locked(ext4_group_lock_ptr(e4b->bd_sb, e4b->bd_group));
	BUG_ON(ex == NULL);

	buddy = mb_find_buddy(e4b, 0, &max);
	BUG_ON(buddy == NULL);
	BUG_ON(block >= max);
    //先遍历0 order的bitmap,如果物理块号block已经分配,直接返回
	if (mb_test_bit(block, buddy)) {
		ex->fe_len = 0;
		ex->fe_start = 0;
		ex->fe_group = 0;
		return 0;
	}

	/* find actual order */
    //order表示的是从block位置开始的空闲的阶(空闲的最小order)
	order = mb_find_order_for_block(e4b, block);
	block = block >> order;

	ex->fe_len = 1 << order;
	ex->fe_start = block << order;
	ex->fe_group = e4b->bd_group;

	/* calc difference from given start */
	next = next - ex->fe_start;
	ex->fe_len -= next;
	ex->fe_start += next;

	while (needed > ex->fe_len &&
	       mb_find_buddy(e4b, order, &max)) {

		if (block + 1 >= max)
			break;

		next = (block + 1) * (1 << order);
		if (mb_test_bit(next, e4b->bd_bitmap))
			break;

		order = mb_find_order_for_block(e4b, next);

		block = next >> order;
		ex->fe_len += 1 << order;
	}

    ...
	return ex->fe_len;
}

函数返回的ex->fe_len是从block物理块号开始的最大连续空间块长度,有可能>=needed参数代表的请求数量,也可能小于needed,即无法从goal目标物理块block开始的连续空闲块不满足needed的申请要求。

ext4_mb_good_group_nolock函数


/*
 * This could return negative error code if something goes wrong
 * during ext4_mb_init_group(). This should not be called with
 * ext4_lock_group() held.
 */
static int ext4_mb_good_group_nolock(struct ext4_allocation_context *ac,
				     ext4_group_t group, int cr)
{
	struct ext4_group_info *grp = ext4_get_group_info(ac->ac_sb, group);
	struct super_block *sb = ac->ac_sb;
	struct ext4_sb_info *sbi = EXT4_SB(sb);
	bool should_lock = ac->ac_flags & EXT4_MB_STRICT_CHECK;
	ext4_grpblk_t free;
	int ret = 0;

	if (should_lock)
		ext4_lock_group(sb, group);
	free = grp->bb_free;
	if (free == 0)
		goto out;
	if (cr <= 2 && free < ac->ac_g_ex.fe_len)
		goto out;
	if (unlikely(EXT4_MB_GRP_BBITMAP_CORRUPT(grp)))
		goto out;
	if (should_lock)
		ext4_unlock_group(sb, group);

    ...

	if (should_lock)
		ext4_lock_group(sb, group);
	ret = ext4_mb_good_group(ac, group, cr);
out:
	if (should_lock)
		ext4_unlock_group(sb, group);
	return ret;
}

 做一些基本判定后调用ext4_mb_good_group函数。

ext4_mb_good_group函数

检查再cr严苛程度下能否完成分配


/*
 * This is also called BEFORE we load the buddy bitmap.
 * Returns either 1 or 0 indicating that the group is either suitable
 * for the allocation or not.
 */
static bool ext4_mb_good_group(struct ext4_allocation_context *ac,
				ext4_group_t group, int cr)
{
	ext4_grpblk_t free, fragments;
	int flex_size = ext4_flex_bg_size(EXT4_SB(ac->ac_sb));
	struct ext4_group_info *grp = ext4_get_group_info(ac->ac_sb, group);

	BUG_ON(cr < 0 || cr >= 4);

	if (unlikely(EXT4_MB_GRP_BBITMAP_CORRUPT(grp)))
		return false;

	free = grp->bb_free;
	if (free == 0)
		return false;

	fragments = grp->bb_fragments;
	if (fragments == 0)
		return false;

	switch (cr) {
	case 0:
		BUG_ON(ac->ac_2order == 0);

		/* Avoid using the first bg of a flexgroup for data files */
        //lex块组的第一个块组一般是给目录和特殊文件用的,当“最严苛的时候”跳过
		if ((ac->ac_flags & EXT4_MB_HINT_DATA) &&
		    (flex_size >= EXT4_FLEX_SIZE_DIR_ALLOC_SCHEME) &&
		    ((group % flex_size) == 0))
			return false;
        //空闲block总数都少于fe_len的话返回false
		if (free < ac->ac_g_ex.fe_len)
			return false;

        //大于13则可以分配
		if (ac->ac_2order > ac->ac_sb->s_blocksize_bits+1)
			return true;
        //最大的空闲order小于申请的order,返回false
		if (grp->bb_largest_free_order < ac->ac_2order)
			return false;

		return true;
	case 1:
        //空闲空间的平均长度大于等于申请的长度,可以进行分配
		if ((free / fragments) >= ac->ac_g_ex.fe_len)
			return true;
		break;
	case 2:
        //空闲的总block树大于申请量就可以申请
		if (free >= ac->ac_g_ex.fe_len)
			return true;
		break;
	case 3:
        //cr=3最不严格,意味只要能有空闲的任何空间满足条件就可以申请
		return true;
	default:
		BUG();
	}

	return false;
}
ext4_mb_complex_scan_group函数

/*
 * The routine scans the group and measures all found extents.
 * In order to optimize scanning, caller must pass number of
 * free blocks in the group, so the routine can know upper limit.
 */
static noinline_for_stack
void ext4_mb_complex_scan_group(struct ext4_allocation_context *ac,
					struct ext4_buddy *e4b)
{
	struct super_block *sb = ac->ac_sb;
	void *bitmap = e4b->bd_bitmap;
	struct ext4_free_extent ex;
	int i;
	int free;

	free = e4b->bd_info->bb_free;
	if (WARN_ON(free <= 0))
		return;
    //从第一个空闲的block开始搜索
	i = e4b->bd_info->bb_first_free;

	while (free && ac->ac_status == AC_STATUS_CONTINUE) {
		i = mb_find_next_zero_bit(bitmap,
						EXT4_CLUSTERS_PER_GROUP(sb), i);
        ...

		mb_find_extent(e4b, i, ac->ac_g_ex.fe_len, &ex);
        ...
		ex.fe_logical = 0xDEADC0DE; /* debug value */
        //检查是否合适
		ext4_mb_measure_extent(ac, &ex, e4b);

		i += ex.fe_len;
		free -= ex.fe_len;
	}

	ext4_mb_check_limits(ac, e4b, 1);
}
ext4_mb_measure_extent函数

/*
 * The routine checks whether found extent is good enough. If it is,
 * then the extent gets marked used and flag is set to the context
 * to stop scanning. Otherwise, the extent is compared with the
 * previous found extent and if new one is better, then it's stored
 * in the context. Later, the best found extent will be used, if
 * mballoc can't find good enough extent.
 *
 * FIXME: real allocation policy is to be designed yet!
 */
static void ext4_mb_measure_extent(struct ext4_allocation_context *ac,
					struct ext4_free_extent *ex,
					struct ext4_buddy *e4b)
{
	struct ext4_free_extent *bex = &ac->ac_b_ex;
	struct ext4_free_extent *gex = &ac->ac_g_ex;


	ac->ac_found++;

	/*
	 * The special case - take what you catch first
	 */
	if (unlikely(ac->ac_flags & EXT4_MB_HINT_FIRST)) {
		*bex = *ex;
		ext4_mb_use_best_found(ac, e4b);
		return;
	}

	/*
	 * Let's check whether the chuck is good enough
	 */
    //如果空闲空间长度刚好跟要求分配的长度一致那么这个就是最佳的
	if (ex->fe_len == gex->fe_len) {
		*bex = *ex;
		ext4_mb_use_best_found(ac, e4b);
		return;
	}

	/*
	 * If this is first found extent, just store it in the context
	 */
	if (bex->fe_len == 0) {
		*bex = *ex;
		return;
	}

	/*
	 * If new found extent is better, store it in the context
	 */

	if (bex->fe_len < gex->fe_len) {
        //如果当前记录的bex不满足分配,那么只要找一个更大的空闲区域,就记录到bex中
		/* if the request isn't satisfied, any found extent
		 * larger than previous best one is better */
		if (ex->fe_len > bex->fe_len)
			*bex = *ex;
	} else if (ex->fe_len > gex->fe_len) {
        //如果已经发现了满足条件的空闲区域记录在bex中,那么就要找到最小能满gex->fe_len的
        //空闲区域即可,避免使用更大的连续空间造成碎片化
		/* if the request is satisfied, then we try to find
		 * an extent that still satisfy the request, but is
		 * smaller than previous one */
		if (ex->fe_len < bex->fe_len)
			*bex = *ex;
	}

	ext4_mb_check_limits(ac, e4b, 0);
}

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

ext4 buddy块分配算法源码剖析 的相关文章

  • 如何调用位于其他目录的Makefile?

    我正在尝试这样做 我想打电话给 make Makefile存在于其他目录中 abc可以使用位于不同目录中的 shell 脚本的路径 我该怎么做呢 由于 shell 脚本不允许我cd进入Makefile目录并执行make 我怎样才能编写she
  • 如何让 clangd 转向 c++20

    当没有其他信息时 如何让 clangd 回退到 c 20 例如 在第一次构建之前 cmake 可以生成一个 这是在带有最新 LLVM 的 Arch Linux 上 这是通过 Emacs LSP 运行的 但这应该没有什么区别 你可以加 Com
  • 标准头文件中的 C 编译器错误 - 未定义的 C++ 定义

    我正在尝试编译 C 程序 但收到许多错误 这些错误是在标准 C 头文件 inttypes h stdio h stat h 等 中遇到的 错误的来源是以下未定义的常量 BEGIN DECLS END DECLS BEGIN NAMESPAC
  • 如何不断刷新屏幕并实时更新[关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我想在linux上写一个C程序 不断刷新屏幕并实时更新 例如类似于top终端中的命令 谁能指出我正确的方向 为了保持它跨终端类型的可移
  • 如何在Python中独立于语言安装(linux)获取用户桌面路径

    我找到了 如何找到用户桌面的路径 的几个问题和答案 但在我看来它们都已失效 至少我找到的那些 原因是 如果用户安装的 Linux 不是英语 他或她的桌面很可能位于除 Desktop 例如 对于瑞典语 我相信它是在 Skrivbord 谁知道
  • Linux shell 脚本:十六进制数字到二进制字符串

    我正在 shell 脚本中寻找一些简单的方法来将十六进制数字转换为 0 和 1 字符的序列 Example 5F gt 01011111 是否有任何命令或简单的方法来完成它 或者我应该为其编写一些开关 echo ibase 16 obase
  • linux x86 汇编语言 sys_read 调用的第一个参数应为 0 (stdin)

    我正在编写一个简单的汇编程序来从标准输入读取 如 scanf 这是我的代码 section bss num resb 5 section txt global start start mov eax 3 sys read mov ebx 0
  • 如何让“grep”从文件中读取模式?

    假设有一个很大的文本文件 我只想打印与某些模式不匹配的行 显然 我可以使用egrep v patter1 pattern2 pattern3 现在 如果所有这些模式都在一个文本文件中怎么办 最好的制作方法是什么egrep从文件中读取模式 g
  • 适用于 KDE 和 Gnome 的 Gui [重复]

    这个问题在这里已经有答案了 我想为一个现在是 CLI 的应用程序编写一个 gui 它需要在 KDE 和 Gnome DE 中 看起来不错 充分利用用户的外观设置 如果我选择 Qt 或 GTK 我能够做到这一点吗 它们与两个 DE 集成良好吗
  • 从多线程程序中调用 system()

    我们正在开发一个用 C 编写的多线程内存消耗应用程序 我们必须执行大量的 shellscript linux 命令 并获取返回码 读完之后article http www linuxprogrammingblog com threads a
  • 如何在特定 systemd 服务重新启动时触发自定义脚本运行

    我想知道如何安排自定义脚本在重新启动服务时运行 我的用例是 每当重新启动 Tomcat 服务时 我都必须运行多个命令 我想知道是否有一种方法可以编写脚本并安排它在重新启动 Tomcat 服务时运行 我已将 tomcat 脚本设置为 syst
  • 为什么 Linux 对目录使用 getdents() 而不是 read()?

    我浏览 K R C 时注意到 为了读取目录中的条目 他们使用了 while read dp gt fd char dirbuf sizeof dirbuf sizeof dirbuf code Where dirbuf是系统特定的目录结构
  • 设置 Apache POI 的路径

    我想创建 Excel 文件并使用 java 程序在该文件中写入数据 That is here http www techbrainwave com p 554我在 java 文件所在的位置提取了 Apache POI 并将该路径包含在路径变
  • .NET Core 中的跨平台文件名处理

    如何处理文件名System IO以跨平台方式运行类以使其在 Windows 和 Linux 上运行 例如 我编写的代码在 Windows 上完美运行 但它不会在 Ubuntu Linux 上创建文件 var tempFilename Dat
  • 如何修复“iptables:没有该名称的链/目标/匹配”?

    我在我的 Linux 嵌入式系统上构建并安装了 iptables 如果我列出所有规则 则一切正常 iptables list Chain INPUT policy ACCEPT target prot opt source destinat
  • Unix 命令列出包含字符串但*不*包含另一个字符串的文件

    如何递归查看包含一个字符串且不包含另一个字符串的文件列表 另外 我的意思是评估文件的文本 而不是文件名 结论 根据评论 我最终使用了 find name html exec grep lR base maps xargs grep L ba
  • 修改linux下的路径

    虽然我认为我已经接近 Linux 专业人士 但显然我仍然是一个初学者 当我登录服务器时 我需要使用最新版本的R 统计软件 R 安装在 2 个地方 当我运行以下命令时 which R I get usr bin R 进而 R version
  • 使用 find - 删除除任何一个之外的所有文件/目录(在 Linux 中)

    如果我们想删除我们使用的所有文件和目录 rm rf 但是 如果我希望一次性删除除一个特定文件之外的所有文件和目录怎么办 有什么命令可以做到这一点吗 rm rf 可以轻松地一次性删除 甚至可以删除我最喜欢的文件 目录 提前致谢 find ht
  • awk 子串单个字符

    这是columns txt aaa bbb 3 ccc ddd 2 eee fff 1 3 3 g 3 hhh i jjj 3 kkk ll 3 mm nn oo 3 我可以找到第二列以 b 开头的行 awk if substr 2 1 1
  • Bash 解析和 shell 扩展

    我对 bash 解析输入和执行扩展的方式感到困惑 对于输入来说 hello world 作为 bash 中的参数传递给显示其输入内容的脚本 我不太确定 Bash 如何解析它 Example var hello world displaywh

随机推荐

  • LaTeX的基本使用

    看前说明 说明 这篇文章介绍了latex的基本使用 基本覆盖了latex入门的知识点 由本人自己学习研究整理出来 不可被他人拿来进行不当的商用等等 违者必究 大家利用下面完整的latex文档 在编译器中编译 对比latex文档和生成文件之间
  • MyEclipse中关闭项目的作用及操作方法

    1 关闭项目的操作方式 选中项目 右键 点击Close Project 便可关闭当前项目 如图 关闭后的项目状态如图所示 2 开启项目的操作方式 双击项目或右键项目 点击Open Project 弹出如下窗口 点击 No 按钮 开启当前项目
  • JUC 之 线程局部变量 ThreadLocal

    ThreadLocal 基本概念 ThreadLocal 提供线程局部变量 这些变量与正常的变量不同 因为每一个线程在访问 ThreadLocal 实例的时候 通过其get 或者 set 方法 都有自己的 独立初始化的变副本 ThreadL
  • react、umi、dva

    React 一 React的简介 1 介绍 React 是一个用于构建用户界面的 JAVASCRIPT 库 React主要用于构建UI 很多人认为 React 是 MVC 中的 V 视图 React 起源于 Facebook 的内部项目 用
  • Mac升级Catalina(10.15)后 clion不能运行,提示「xcrun: error: invalid active developer path ...」

    Mac升级Catalina 10 15 后 使用clion 运行失败 提示内容如下 xcrun error invalid active developer path Library Developer CommandLineTools m
  • MQTT-保留消息和遗嘱消息

    遗嘱消息 为什么需要遗嘱消息 MQTT的订阅发布机制 解耦了消息的发送方和接收方 这使我们没有办法获取对端的状态 为了解决该问题 MQTT提供了遗嘱消息 为意外断线的客户端提供了对外发出通知的能力 如何使用遗嘱消息 使用遗嘱消息 客户端需要
  • 【笔记】关于win导入外部动态磁盘时“包名称无效”的解决办法

    网易博客搬家 原贴时间 2015 02 22 一 问题背景 硬盘闲置 电脑重装系统以后装上硬盘 计算机 中无盘符 磁盘管理中显示硬盘为 外部动态磁盘 右键 导入外部磁盘 提示 包名称错误 二 尝试过程 1 重启电脑 无效 2 换sata接口
  • DBeaver教程:连接达梦数据库DM8

    本文介绍如何通过dbeaver连接达梦数据库进行管理 DBeaver 是一个基于 Java 开发 免费开源的通用数据库管理和开发 DBeaver 采用 Eclipse 框架开发 支持插件扩展 并且提供了许多数据库管理工具 ER 图 数据导入
  • linux查看所有文件

    这本阿里P8撰写的算法笔记 再次推荐给大家 身边不少朋友学完这本书最后加入大厂 Github 疯传 史上最强悍 阿里大佬 LeetCode刷题手册 开放下载了 1 linux文件结构 linux文件结构是树形的 根目录是 其它所有文件都是在
  • OCR加持白描App,让AI成为视障者的眼睛

    现实中 你可以轻松无障碍地阅读各类平面印刷文字以及身边的一切 或许你未曾想过 视障人群该怎么办呢 统计数据显示 中国大约有1700万的视障群体 相当于每100个人中就有超过1位是视障人士 但我们在日常生活中却很少见到他们 那是因为视障群体在
  • 3、ARIMA序列预测Matlab代码、可视化(可做算法对比)

    1 文件包中程序均收集 整理 汇总自网络 2 文件包完整内容 1 ARIMA 功能函数 仅包含一个ARIMA算法函数 需要调用到自己的程序中使用 函数部分代码及预览图 function result ARIMA algorithm data
  • 应用程序本地化

    一 简介 使用本地化功能 可以轻松地将应用程序翻译成多种语言 甚至可以翻译成同一语言的多种方言 如果要添加本地化功能 需要为每种支持的语言创建一个子目录 称为 本地化文件夹 通常使用 lproj作为拓展名 当本地化的应用程序需要载入某一资源
  • pytorch 中register_buffer()

    今天在看DSSINet代码的ssim py时 遇到了一个用法 class NORMMSSSIM torch nn Module def init self sigma 1 0 levels 5 size average True chann
  • Docker网络体系结构:设计可扩展、可移植的Docker容器网络

    原文地址 译者 本人翻译水平有限 目的仅是为了学好Docker 如有错误请见谅 翻译版本 v1 01 将不断优化翻译质量 本文包含以下内容 Docker容器就是将应用及其所依赖运行环境的完整文件系统打成一个包 包括所需代码 运行库 系统工具
  • 一文读懂人脸识别技术

    2019 08 27 17 06 26 本文内容涵盖人脸识别发展历程 市场研究 核心技术 商业应用以及产业落地 个人看法等干货研究 注意 本文干货满满 约有2万7千字 强烈建议大家先收藏后学习 01 发展史 1 人脸识别的理解 人脸识别 F
  • DJANGO增删改查

    https www cnblogs com yuanlianghong p 10987877 html 一 Django的工作流 1 用户通过浏览器输入相应的 URL 发起 HTTP 请求 一般是 GET POST 2 Django 接受到
  • 微信小程序:初识微信小程序和前端

    一 前期准备工作 1 申请开发微信小程序 登录微信公众平台 gt 点击 小程序 gt 点击 前往注册 gt 注册成功即可 2 下载微信开发者工具 小程序文档 gt 工具中的下载 gt 下载自己需要的版本 3 在开发者工具中创建项目 这个当中
  • RabbitMQ的高级特性

    RabbitMQ的高级特性 在项目中 有一些无需即时返回且耗时的操作 我们可以将其提取出来 做异步处理 从而节省服务器的请求响应时间 从而提高系统的吞吐量 这就需要使用到MQ 而常见的RabbitMQ就是重中之重 之前说了他的几个常见的用处
  • WebSocket 的使用,和客户端断电,服务器检测断开连接

    WebSocket 的使用 和客户端断电 服务器检测断开连接 服务器用WebSocketServlet 实例化自定义的MessageInbound web xml中配置socket
  • ext4 buddy块分配算法源码剖析

    概述 ext4 buddy块分配算法的函数是ext4 mb regular allocator 阅读本文之前需要先看下ext4 mballoc之buddy算法 nginux的博客 CSDN博客 ext4 mb regular allocat