<?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>HU Xiaoxu &#8211; HU Xiaoxu</title>
	<atom:link href="https://blog.ihuxu.com/author/admin/feed/" rel="self" type="application/rss+xml" />
	<link>https://blog.ihuxu.com</link>
	<description>a software engineer&#039;s blog</description>
	<lastBuildDate>Mon, 22 Sep 2025 08:14:41 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.6.2</generator>
	<item>
		<title>The Advantages of UV over PIP</title>
		<link>https://blog.ihuxu.com/the-advantages-of-uv-over-pip/</link>
					<comments>https://blog.ihuxu.com/the-advantages-of-uv-over-pip/#respond</comments>
		
		<dc:creator><![CDATA[HU Xiaoxu]]></dc:creator>
		<pubDate>Mon, 22 Sep 2025 04:57:00 +0000</pubDate>
				<category><![CDATA[Computer Science]]></category>
		<category><![CDATA[Dev Tool]]></category>
		<category><![CDATA[uv]]></category>
		<guid isPermaLink="false">https://blog.ihuxu.com/?p=12673</guid>

					<description><![CDATA[Let&#8217;s go through the advantages of uv (github) over pip with the following a few aspects. Positioning Performance Virtual Environment Support Dependency Resolution Cross-Platform Experiences In summary, while pip remains the standard and most widely adopted tool, uv offers a modern, high-performance alternative that simplifies Python package management. It&#8217;s still early days for uv, but it&#8217;s worth keeping an eye on as the ecosystem matures.]]></description>
		
					<wfw:commentRss>https://blog.ihuxu.com/the-advantages-of-uv-over-pip/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>How to Expose the Kubernetes Service via  NodePort</title>
		<link>https://blog.ihuxu.com/how-to-expose-the-kubernetes-service-via-nodeport/</link>
					<comments>https://blog.ihuxu.com/how-to-expose-the-kubernetes-service-via-nodeport/#respond</comments>
		
		<dc:creator><![CDATA[HU Xiaoxu]]></dc:creator>
		<pubDate>Wed, 03 Sep 2025 14:25:52 +0000</pubDate>
				<category><![CDATA[Computer Science]]></category>
		<category><![CDATA[DevOps]]></category>
		<category><![CDATA[K8s]]></category>
		<category><![CDATA[NodePort]]></category>
		<guid isPermaLink="false">https://blog.ihuxu.com/?p=12669</guid>

					<description><![CDATA[In the previous article, we discussed the ClusterIP service type. In this one, we&#8217;ll briefly cover the NodePort service type, which allows us to expose a service as an entry point to the public network. Kubernetes Manifests Example As we can see from the above K8s manifests You can run the following commands to try this out locally using kind. Firstly, we need to configure the cluster to map your<div class="read-more"><a class="btn read-more-btn" href="https://blog.ihuxu.com/how-to-expose-the-kubernetes-service-via-nodeport/">Read More</a></div>]]></description>
		
					<wfw:commentRss>https://blog.ihuxu.com/how-to-expose-the-kubernetes-service-via-nodeport/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>How the Kubernetes ClusterIP Service Works</title>
		<link>https://blog.ihuxu.com/how-the-kubernetes-clusterip-service-works/</link>
					<comments>https://blog.ihuxu.com/how-the-kubernetes-clusterip-service-works/#respond</comments>
		
		<dc:creator><![CDATA[HU Xiaoxu]]></dc:creator>
		<pubDate>Mon, 01 Sep 2025 16:11:01 +0000</pubDate>
				<category><![CDATA[Computer Science]]></category>
		<category><![CDATA[DevOps]]></category>
		<category><![CDATA[ClusterIP]]></category>
		<category><![CDATA[K8s]]></category>
		<guid isPermaLink="false">https://blog.ihuxu.com/?p=12665</guid>

					<description><![CDATA[A ClusterIP Service is the default Kubernetes service type. It provides a virtual IP address (VIP) inside the cluster to allow pods to communicate with each other. It is internal-only, meaning it is not accessible from outside the cluster. Example Manifests You can try it out by running the following commands Apply the Kubernetes manifest to the test cluster kind-my-cluster. If the test cluster doesn’t exist, you can create it<div class="read-more"><a class="btn read-more-btn" href="https://blog.ihuxu.com/how-the-kubernetes-clusterip-service-works/">Read More</a></div>]]></description>
		
					<wfw:commentRss>https://blog.ihuxu.com/how-the-kubernetes-clusterip-service-works/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>From Polling to QUIC: How Modern Web Communication Works</title>
		<link>https://blog.ihuxu.com/from-polling-to-quic-how-modern-web-communication-works/</link>
					<comments>https://blog.ihuxu.com/from-polling-to-quic-how-modern-web-communication-works/#respond</comments>
		
		<dc:creator><![CDATA[HU Xiaoxu]]></dc:creator>
		<pubDate>Thu, 21 Aug 2025 17:40:58 +0000</pubDate>
				<category><![CDATA[Computer Network]]></category>
		<category><![CDATA[Computer Science]]></category>
		<category><![CDATA[Foundation]]></category>
		<category><![CDATA[HTTP]]></category>
		<category><![CDATA[Long Polling]]></category>
		<category><![CDATA[QUIC]]></category>
		<category><![CDATA[SSE]]></category>
		<category><![CDATA[WebSocket]]></category>
		<guid isPermaLink="false">https://blog.ihuxu.com/?p=12661</guid>

					<description><![CDATA[Today, I’m revisiting client-server communication mechanisms. The main methods are outlined in the table below for easier understanding. Mechanism Based on Direction Pros Cons Typical Use Cases Polling HTTP/1.x Client → Server • Very simple to implement• Works everywhere • High latency (depends on interval)• High overhead (many HTTP headers &#38; TCP handshakes)• Wastes resources Periodic updates, legacy apps Long Polling HTTP/1.x Pseudo Client ⇄ Server • Lower latency than<div class="read-more"><a class="btn read-more-btn" href="https://blog.ihuxu.com/from-polling-to-quic-how-modern-web-communication-works/">Read More</a></div>]]></description>
		
					<wfw:commentRss>https://blog.ihuxu.com/from-polling-to-quic-how-modern-web-communication-works/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>New Features from C++20 Release</title>
		<link>https://blog.ihuxu.com/new-features-from-c20-release/</link>
					<comments>https://blog.ihuxu.com/new-features-from-c20-release/#respond</comments>
		
		<dc:creator><![CDATA[HU Xiaoxu]]></dc:creator>
		<pubDate>Mon, 30 Jun 2025 12:40:00 +0000</pubDate>
				<category><![CDATA[C/C++]]></category>
		<category><![CDATA[Computer Language]]></category>
		<category><![CDATA[Computer Science]]></category>
		<category><![CDATA[C++]]></category>
		<guid isPermaLink="false">https://blog.ihuxu.com/?p=12609</guid>

					<description><![CDATA[I recently did a quick study of the new features introduced in C++20, and I’d like to summarize what I’ve learned here. Core Languages Enhancements constinit &#38; consteval &#38; enhanced constexpr The above three keywords enable code to be evaluated or initialized at compile time. The main goal of these keywords, from my perspective, are shown as following: template parameters in lambadas As shown in the code snippet above, templates<div class="read-more"><a class="btn read-more-btn" href="https://blog.ihuxu.com/new-features-from-c20-release/">Read More</a></div>]]></description>
		
					<wfw:commentRss>https://blog.ihuxu.com/new-features-from-c20-release/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Duolingo to Replace Contractors with AI</title>
		<link>https://blog.ihuxu.com/duolingo-to-replace-contractors-with-ai/</link>
					<comments>https://blog.ihuxu.com/duolingo-to-replace-contractors-with-ai/#respond</comments>
		
		<dc:creator><![CDATA[HU Xiaoxu]]></dc:creator>
		<pubDate>Thu, 01 May 2025 00:08:00 +0000</pubDate>
				<category><![CDATA[Industry News]]></category>
		<category><![CDATA[AI]]></category>
		<category><![CDATA[Duolingo]]></category>
		<guid isPermaLink="false">https://blog.ihuxu.com/?p=12548</guid>

					<description><![CDATA[Today, I came across an internal email from Duolingo&#8217;s all-hands, announcing that Duolingo is going to make a significant platform shift &#8211; AI-first. Luis, the CEO, believes that AI is happening and changing much of how they work today, they can&#8217;t wait until the AI is 100% perfect, and would rather move with urgency and take occasional small hits on quality. Also some constructive constraints are raised from him, one<div class="read-more"><a class="btn read-more-btn" href="https://blog.ihuxu.com/duolingo-to-replace-contractors-with-ai/">Read More</a></div>]]></description>
		
					<wfw:commentRss>https://blog.ihuxu.com/duolingo-to-replace-contractors-with-ai/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>How to Terminate Other Child Threads Based on the Processing Result of Some One Child Thread in Java</title>
		<link>https://blog.ihuxu.com/how-to-terminate-other-child-threads-based-on-the-processing-result-of-some-one-child-thread-in-java/</link>
					<comments>https://blog.ihuxu.com/how-to-terminate-other-child-threads-based-on-the-processing-result-of-some-one-child-thread-in-java/#respond</comments>
		
		<dc:creator><![CDATA[HU Xiaoxu]]></dc:creator>
		<pubDate>Mon, 15 Apr 2024 04:45:58 +0000</pubDate>
				<category><![CDATA[Computer Language]]></category>
		<category><![CDATA[Computer Science]]></category>
		<category><![CDATA[JAVA]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Thread]]></category>
		<guid isPermaLink="false">https://blog.ihuxu.com/?p=12496</guid>

					<description><![CDATA[Problem In the parent thread, several child threads will be forked. It needs to determine whether to terminate the execution of other child threads based on the processing result of some one child thread. Requirement Assumption As depicted above, given that the order attribute of child thread 2 is set to 1, its execution result will be processed with priority. Assuming that the execution result of child thread 2 is<div class="read-more"><a class="btn read-more-btn" href="https://blog.ihuxu.com/how-to-terminate-other-child-threads-based-on-the-processing-result-of-some-one-child-thread-in-java/">Read More</a></div>]]></description>
		
					<wfw:commentRss>https://blog.ihuxu.com/how-to-terminate-other-child-threads-based-on-the-processing-result-of-some-one-child-thread-in-java/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Home Assistant Add-on: FRP Client</title>
		<link>https://blog.ihuxu.com/home-assistant-add-on-frp-client/</link>
					<comments>https://blog.ihuxu.com/home-assistant-add-on-frp-client/#respond</comments>
		
		<dc:creator><![CDATA[HU Xiaoxu]]></dc:creator>
		<pubDate>Sun, 03 Mar 2024 04:14:19 +0000</pubDate>
				<category><![CDATA[Computer Science]]></category>
		<category><![CDATA[My Project]]></category>
		<category><![CDATA[Addon]]></category>
		<category><![CDATA[FRP]]></category>
		<category><![CDATA[Home Assistant]]></category>
		<guid isPermaLink="false">https://blog.ihuxu.com/?p=12469</guid>

					<description><![CDATA[BackgroundI’m trying to enable remote access to my local Home Assistant OS installed on my Raspberry Pi 4, so that I can upload my location to the HAOS while I’m outside. Therefore, I’ve authored an add-on to achieve that by leveraging the FRP software, which can forward traffic from my online server with public IP to the local HAOS. Architecture Github RepoGitHub &#8211; huxiaoxu2019/hass-addon-frp-client: Home Assistant Community Add-on: FRP Client&#160;37<div class="read-more"><a class="btn read-more-btn" href="https://blog.ihuxu.com/home-assistant-add-on-frp-client/">Read More</a></div>]]></description>
		
					<wfw:commentRss>https://blog.ihuxu.com/home-assistant-add-on-frp-client/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>60 分钟搞定 Tarjan 算法求解无向图的割点与桥</title>
		<link>https://blog.ihuxu.com/tarjan-algorithm-and-cut-points-and-bridges-for-undirected-graphs/</link>
					<comments>https://blog.ihuxu.com/tarjan-algorithm-and-cut-points-and-bridges-for-undirected-graphs/#respond</comments>
		
		<dc:creator><![CDATA[HU Xiaoxu]]></dc:creator>
		<pubDate>Mon, 09 Dec 2019 16:09:16 +0000</pubDate>
				<category><![CDATA[Computer Science]]></category>
		<category><![CDATA[Data Structure and Algorithm]]></category>
		<category><![CDATA[Graph]]></category>
		<category><![CDATA[Original]]></category>
		<category><![CDATA[Tarjan]]></category>
		<guid isPermaLink="false">https://blog.ihuxu.com/?p=12052</guid>

					<description><![CDATA[本人在学习 Tarjan 算法求解无向图的割点与桥的问题时，很快发现了一篇简洁易懂的文章。很顺利地了解算法的思路，并写出了“高效”的代码，此时内心飘过 —— So Easy。然而，当我翻开《算法竞赛进阶指南》这本书的有关篇章时，我发现其中经过精简优化的代码有几条语句让我不得其所。以至于，花了较多心思和时间来思考🤔这段真正高效的 Tarjan 算法的工作原理以及代码的编写。 关于 Tarjan 算法，我将会写若干篇系列文章，来完整系统地介绍 Tarjan 算法的原理以及其主要解决的问题。而在本章我主要讲一个问题 —— 如何使用 Tarjan 算法求解无向图的割点与桥。 在讲述问题之前，我们先来简单地了解下什么是 Tarjan 算法？ Tarjan 算法 Tarjan 算法是基于深度优先搜索的算法，用于求解图的连通性问题。Tarjan 算法可以在线性时间内求出无向图的割点与桥，进一步地可以求解无向图的双连通分量；同时，也可以求解有向图的强连通分量、必经点与必经边。 如果，你对上面的一些术语不是很了解，那么也毫无关系。目前为止，我们只要知道 Tarjan 算法是基于深度优先搜索的，用于求解图的连通性问题的算法就好了。 提到 Tarjan，不得不提的就是算法的作者 —— Robert Tarjan。他可是一名著名的计算机科学家，我们耳熟能详的最近公共祖先（LCA）问题、强连通分量问题、双连通分量问题的高效算法都是由他发现并解决的，同时他还参与了开发斐波那契堆、伸展树的工作。 无向图的割点与桥 首先，什么是无向图？简单说，若一个图中每条边都是无方向的，则称为无向图。 割点 若从图中删除节点 以及所有与 关联的边之后，图将被分成两个或两个以上的不相连的子图，那么称 为图的割点。 桥 若从图中删除边 之后，图将分裂成两个不相连的子图，那么称 为图的桥或割边。 如何求解图的割点与桥？ 那么，在了解了 Tarjan 算法的背景以及图的割点与桥的基本概念之后，我们下面所面临的问题就是 —— 如何求解图的割点与桥？ 在这里，我们开门见山，直接引出 Tarjan 算法在求解无向图的割点与桥的工作原理。 时间戳 时间戳是用来标记图中每个节点在进行深度优先搜索时被访问的时间顺序，当然，你可以理解成一个序号（这个序号由小到大），用 来表示。 搜索树 在无向图中，我们以某一个节点 出发进行深度优先搜索，每一个节点只访问一次，所有被访问过的节点与边构成一棵树，我们可以称之为“无向连通图的搜索树”。 追溯值 追溯值用来表示从当前节点 作为搜索树的根节点出发，能够访问到的所有节点中，时间戳最小的值 —— 。那么，我们要限定下什么是“能够访问到的所有节点”？，其需要满足下面的条件之一即可： 是的，你可能觉得这段话太绕了，那么我们通过动画的方式来摸你追溯值真实计算过程。 在上面的计算过程中，我们可以认为以序号 为根的搜索树的节点有 。上面所说的“通过一条非搜索树上的边”可以理解成动画中的 这条边，“能够到达搜索树的所有节点”即为节点 。<div class="read-more"><a class="btn read-more-btn" href="https://blog.ihuxu.com/tarjan-algorithm-and-cut-points-and-bridges-for-undirected-graphs/">Read More</a></div>]]></description>
		
					<wfw:commentRss>https://blog.ihuxu.com/tarjan-algorithm-and-cut-points-and-bridges-for-undirected-graphs/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		<enclosure url="https://blog.ihuxu.com/wp-content/uploads/2024/04/v3_6cd03b2c-3292-11ea-8fc1-165bd6f00369_1.mp4" length="104155" type="video/mp4" />
<enclosure url="https://blog.ihuxu.com/wp-content/uploads/2024/04/v3_1d8dc54c-3293-11ea-adeb-8e79ebed40e0_1.mp4" length="26240" type="video/mp4" />

			</item>
		<item>
		<title>递归</title>
		<link>https://blog.ihuxu.com/recursive/</link>
					<comments>https://blog.ihuxu.com/recursive/#respond</comments>
		
		<dc:creator><![CDATA[HU Xiaoxu]]></dc:creator>
		<pubDate>Wed, 04 Dec 2019 16:38:43 +0000</pubDate>
				<category><![CDATA[Basic Algorithm]]></category>
		<category><![CDATA[Computer Science]]></category>
		<category><![CDATA[Data Structure and Algorithm]]></category>
		<category><![CDATA[Original]]></category>
		<category><![CDATA[Recursive]]></category>
		<guid isPermaLink="false">http://blog.ihuxu.com/?p=11712</guid>

					<description><![CDATA[递归是什么？ 递归（英语：Recursion），又译为递回，在数学与计算机科学中，是指在函数的定义中使用函数自身的方法 。 维基百科 简单说，就是自身调用自身。 为什么使用递归？ 往往面对一类问题时，如果它的规模足够小或者说达到既定的边界条件时，我们可以直接获取答案。但是，当这类问题的规模比较大时，却往往无法直接获取答案。那么，这个时候就可以通过“自身调用自身”的方式，来不断地减小问题的规模，直到问题的规模被缩减到足够小时，直接将答案返回上层的调用者，最终获取到原问题的解。如果将求解的过程逆过来，那么就是所谓的递推。 通过这种方式，我们可以写出“优雅”的代码去解决规模比较大的问题。进而，避免了通过递推的方式，在每一次递推时产生的复杂的条件判断的问题。 上文中提到经过递归调用，会不断地减小问题的规模，有些作者认为这是一种减治法。 递归的特性 自身调用自身 在上文中，已经提到了这个特性，而且也非常好理解，不再赘述。 回溯时还原现场 在使用递归方法时，其中有一个不得不提的特性——回溯时还原现场。 通过递归调用，程序将执行到极限触达边界条件时，就需要将当前层的调用跳出“调用栈”，在跳出“调用栈”时，需要将一些状态信息还原到上一层场景所属的状态，即所谓的回溯时还原场景。 举个例子 有一颗二叉树，求解。代表以root为根的树的最大高度，即。 首先，我们要定义一个递归函数。在定义函数之前，我们要明确两个重要的事情： 函数的含义，代表了递归函数能为我们解决什么样的问题。在这里，我们定义函数的含义为求解某一个子树的高度。 函数的参数，代表了递归函数求解的问题的规模。在这里，我们定义函数的参数为当前需要遍历的节点 —— 以当前节点为根的子树（问题规模）。 在明确了这两件事情之后，面对一个规模较大的、复杂的问题就会变的简单得多。 下面，我们来看看在使用递归函数解决当前问题的整个过程。 递归求解树的最大高度 记忆化递归 通过上面简单的例子，我们了解了如何通过递归解决一个较大规模的问题。但是，我们会发现，使用递归函数解决的每个子问题的解仅仅被使用了一次。然而，在某些复杂的场景，子问题的解可能被使用若干次。那么这个时候，可以考虑加上备忘录法进行优化，即记忆化递归。 递归 —— 这种方法的思考方式是自顶向下的，也就是说符合我们常人在解决问题时的正向思考的过程。这与动态规划 —— 自底向上的方法恰恰相反（记忆化递归与动态规划的问题，我将在后续的篇章中讲解）。 三个经典问题 递归实现指数型枚举 从 ~ 这 个整数中随机选取任意多个，输出所有可能的选择方案。 在最开始学习算法时，面对这种类似的问题我思考了好久。当打开大牛的代码时，才恍然大悟，原来可以用这么简洁的代码解决 —— 递归。 那么，先来分析下这个“小”问题。我们需要在一个序列中随机选取任意多个数字，也就是说每一个数字都有两种可能——选择或不选择。那么，一共的可能的方案总数即 —— 那么，根据上文提到的方案，我们先来确认两件事情： 明确这两件事情之后，我们还需要一个额外的全局变量（），用来保留递归过程中产生的状态信息 —— 当前调用栈被选中的数字。 时间复杂度 每一个数字有两种可能 —— 选择或不选择 递归实现组合型枚举 从 ~ 这 个整数中随机选出 个，输出所有可能的选择方案。 这个问题与上面的问题的唯一区别是限定了选定元素的个数。 很自然地我们可以想到，在输出答案时我们只需要判断下结果集变量 —— 的大小是不是即可。当然，我们也可以在每次搜索时进行判断 —— 剪枝法，这样可以带来性能上的提升。 时间复杂度 我们可以通过判断当前调用栈中的中的数字个数如果大于，或者加上剩余的所有数字都达不到个的话，那么直接返回，跳出调用栈，进行其他情况的搜索。这样，避免了无谓的搜索，只关心满足条件的结果集。所以时间复杂度就从 降到了 。 递归实现排列型枚举 把 ~<div class="read-more"><a class="btn read-more-btn" href="https://blog.ihuxu.com/recursive/">Read More</a></div>]]></description>
		
					<wfw:commentRss>https://blog.ihuxu.com/recursive/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		<enclosure url="https://qoogle.top/wp-content/uploads/2019/12/演示文稿-1.mp4" length="1596806" type="video/mp4" />

			</item>
		<item>
		<title>后缀数组（Suffix Array）</title>
		<link>https://blog.ihuxu.com/suffix-array/</link>
					<comments>https://blog.ihuxu.com/suffix-array/#respond</comments>
		
		<dc:creator><![CDATA[HU Xiaoxu]]></dc:creator>
		<pubDate>Tue, 22 Oct 2019 09:14:45 +0000</pubDate>
				<category><![CDATA[Basic Data Structure]]></category>
		<category><![CDATA[Computer Science]]></category>
		<category><![CDATA[Data Structure and Algorithm]]></category>
		<category><![CDATA[Original]]></category>
		<category><![CDATA[String]]></category>
		<category><![CDATA[Suffix Array]]></category>
		<guid isPermaLink="false">http://blog.ihuxu.com/?p=11466</guid>

					<description><![CDATA[本文介绍后缀数组的定义与构建的过程。首先，文章介绍什么是后缀数组，随后讲解了最自然的朴素算法。为了引出更高效的算法，文章提及了倍增思想与基数排序的背景基础知识。接着，通过模拟演练的方式一步一步地演示如何创建后缀数组。将构建的抽象过程形象地展示出来，使读者更易理解。 定义 给定字符串，其所有后缀有。（6为字符串的长度）。如下所示： S = "banana" s1 = "banana" s2 = "anana" s3 = "nana" s4 = "ana" s5 = "na" s6 = "a" 后缀数组即为由构成的有序的（字典序升序排列的）字符串数组。 构建后缀数组的动态过程演示动画： https://visualgo.net/zh/suffixarray 思路 如何构建后缀数组？ 若字符串的长度为，那么有个后缀。先考虑朴素算法，将个字符串进行排序，需要，此外每一次比较两个字符串大小时需要枚举字符串的长度。故： 时间复杂度： 倍增思想 朴素算法是将所有后缀字符串进行排序，其中每一个都是完整的后缀。那么，这里能否从后缀字符串的长度入手，以后缀字符串的长度为规模将问题进行分解——先排序后缀字符串长度较小的情况，再排序长度较大的情况，依次递推。 那么，在递增后缀字符串的长度时，如果以线性方式进行递推，那么在时间上仍然不会有很好的改善。此时，可以通过成倍增长（倍增）的方式进行递推，只递推状态空间中在2的整数次幂位置上的值。在计算某一个值时，可以利用之前计算过的状态空间的值拼成所需的值即可。 在计算每一个后缀字符串长度时，两两比较字符串只需要的时间，将当前长度的后缀进行排序需要的时间为。长度递增次，所以一共需要的时间为。 基数排序 我们知道基数排序是一种稳定的（大小相同的元素在排序后，其相对位置不变）线性时间复杂度——的排序算法，可以将其融入到上述中的字符串排序中。可以将时间复杂度整体降到。 模拟演算 排序长度为的后缀数组 使用ASCII计算每一个后缀数组的第一个字符的权重（Rank）。 Index Suffix Rank 0 banana 2 1 anana 1 2 nana 14 3 ana 1 4 na 14 5 a 1 为了能够计算出长度为2的后缀数组的顺序，还需要保留右边相邻字符的权重（Next Rank）。如果，当前字符已为最后一个，那么相邻字符的权重可认为是最小值0。 Index Suffix Rank Next Rank 0 banana<div class="read-more"><a class="btn read-more-btn" href="https://blog.ihuxu.com/suffix-array/">Read More</a></div>]]></description>
		
					<wfw:commentRss>https://blog.ihuxu.com/suffix-array/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>树状数组（Binary Indexed Tree）</title>
		<link>https://blog.ihuxu.com/binary-indexed-tree/</link>
					<comments>https://blog.ihuxu.com/binary-indexed-tree/#respond</comments>
		
		<dc:creator><![CDATA[HU Xiaoxu]]></dc:creator>
		<pubDate>Thu, 10 Oct 2019 16:04:30 +0000</pubDate>
				<category><![CDATA[Advanced Data Structure]]></category>
		<category><![CDATA[Computer Science]]></category>
		<category><![CDATA[Data Structure and Algorithm]]></category>
		<category><![CDATA[Binary Indexed Tree]]></category>
		<category><![CDATA[Original]]></category>
		<guid isPermaLink="false">https://blog.ihuxu.com/?p=12051</guid>

					<description><![CDATA[树状数组或二叉索引树（英语：Binary Indexed Tree），又以其发明者命名为Fenwick树。其初衷是解决数据压缩里的累积频率（Cumulative Frequency）的计算问题，现多用于高效计算数列的前缀和， 区间和。它可以以的时间得到任意前缀和，并同时支持在时间内支持动态单点值的修改。空间复杂度。 摘自维基百科 文章先介绍低位运算（lowbit）的基本知识，再提及如何将一个整数划分为个区间的运算过程，进而延展到如何将线性序列以树行结构进行存取，接着介绍了高级数据结构——树状数组的两个基本操作——查询前缀和与单点增加，最后介绍了树状数组的一个应用——求解逆序对数。 lowbit（低位）运算 定义为非负整数在二进制表示下“最低位的1及其后边所有的0”构成的数值。 比如：，其二进制表示为 ，则其低位。 公式 如何计算一个整数中二进制表示下所有位是1的数值？ 比如，则其二进制表示下所有位是1的数值有：，。 朴素算法需要枚举整数中所有的位，时间复杂度为，为整数的二进制表示下的位数。 为了高效获取二进制表示下所有位是1的数值，可以利用运算，得到时间复杂度，为二进制表示下为1的位的个数。 比如，；接着另，则；接着另，停止。 为了得到的第几位为1，可以对2和8分别取对数，即, 。由于C++ math.h 库的函数是以为底的实数运算，并且复杂度常数较大，所以可以通过预处理，利用哈希表来代替运算。 代码 树状数组 假设整数，其二进制表示形式为： 代表二进制表示下位为1的索引下标值，且假设。 那么，可以将区间划分成个小区间 比如，，那么区间可以划分成, 和，其区间长度分别为, 和. 利用运算计算区间： 树状数组是基于以上思想的数据结构，基本用途是维护序列的前缀和。 那么，假设有序列，现在的问题就是如何将这个序列划分成个小区间。不妨，利用序列的索引值（以1为起点开始计数），根据上述计算区间的方式，将其以如下树形结构展开。 此时，以树形结构展开的序列A中的每一个节点都对应着树状数组中的一个值。那么这个值为以当前节点为根的子树中所有节点值的总和。 接着，我们看下以树形结构展开的树状数组是什么样的。 上图中最大的区别是某些节点中的值发生了变化。这是因为，在以树形结构展开的树状数组中的每一个值代表的是一个区间的总和。这个区间即为我们上述求解的区间，比如一个整数7，可以将其划分成, 和三个小区间。那么，这三个小区间的右端值作为索引对应的树状数组中的值即为当前区间元素的总和。 比如对应的树状数组的值为（BIT Value）10，它代表这个区间的和。 再比如对应的树状数组的值为11，它代表这个区间的和。 基本操作 树状数组支持两个基本操作——查询前缀和，单点增加。 查询前缀和 在寻求序列A的前n项的前缀和时，等于n代表的个区间的总和。 单点增加 观察父子节点的关系，可以推算出，父节点的索引parent(i)，为其子节点索引值 + 其低位——。 关于查询前缀和与单点增加的计算过程，可以观看下面视频展示的动画。 树状数组与逆序对 对于一个序列，如果，并且，那么则称与构成逆序对。利用树状数组数据结构可以求解序列中的逆序对个数。 在每一次更新（）树状数组时，以元素的值作为树状数组的索引，更新的值为+1，代表个数。 在每一次获取（）逆序对数时，存在于树状数组中的元素的索引值都比当前元素的大（逆序遍历），那么自然获取到的树状数组的值即为索引值比当前元素的大，且值比当前元素的小的个数。 注意，上述的求解过程时，如果序列A的值范围较大时，那么需要离散化处理。 参考]]></description>
		
					<wfw:commentRss>https://blog.ihuxu.com/binary-indexed-tree/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>动态规划与分治法的思考</title>
		<link>https://blog.ihuxu.com/thoughts-on-dynamic-planning-and-dividing-and-conquer-method/</link>
					<comments>https://blog.ihuxu.com/thoughts-on-dynamic-planning-and-dividing-and-conquer-method/#respond</comments>
		
		<dc:creator><![CDATA[HU Xiaoxu]]></dc:creator>
		<pubDate>Tue, 01 Jan 2019 10:55:27 +0000</pubDate>
				<category><![CDATA[Basic Algorithm]]></category>
		<category><![CDATA[Computer Science]]></category>
		<category><![CDATA[Data Structure and Algorithm]]></category>
		<category><![CDATA[Dynamic Programming]]></category>
		<category><![CDATA[Original]]></category>
		<guid isPermaLink="false">http://blog.ihuxu.com/?p=9939</guid>

					<description><![CDATA[如果一个问题具有最优子结构的性质，此外子问题具有重叠性质，那么可以采用自底向上的动态规划的思路进行求解。 同时，往往可以用递归的方式自顶向地进行求解，即分治法。 如果用分治法去求解这个问题时，能够利用备忘录法进行避免对于子问题的重复计算，那么其计算的效率可以和动态规划的计算效率相比。]]></description>
		
					<wfw:commentRss>https://blog.ihuxu.com/thoughts-on-dynamic-planning-and-dividing-and-conquer-method/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>分治法与回溯法的思考</title>
		<link>https://blog.ihuxu.com/thoughts-on-divide-and-conquer-and-backtracking/</link>
					<comments>https://blog.ihuxu.com/thoughts-on-divide-and-conquer-and-backtracking/#respond</comments>
		
		<dc:creator><![CDATA[HU Xiaoxu]]></dc:creator>
		<pubDate>Tue, 01 Jan 2019 10:39:37 +0000</pubDate>
				<category><![CDATA[Basic Algorithm]]></category>
		<category><![CDATA[Computer Science]]></category>
		<category><![CDATA[Data Structure and Algorithm]]></category>
		<category><![CDATA[Back Tracking]]></category>
		<category><![CDATA[DFS]]></category>
		<category><![CDATA[Divide and Conquer]]></category>
		<category><![CDATA[Original]]></category>
		<guid isPermaLink="false">http://blog.ihuxu.com/?p=9935</guid>

					<description><![CDATA[共同的递归性质 在广义上来说，所有递归的算法都属于分治法。无非是将问题分解成一个规模更小的问题，还是将问题分解成若干个，甚至和输入规模多项式级别的子问题。那么对于前者，有些作者称作是减治法，后者称作分治法。 那么对于回溯法（以深度优先搜搜方式进行）来说，目前为止我见过的都是通过递归的形式来实现的，那么从这个意义上来讲，回溯算法就是分治法的一种。 回溯状态的有无 再说，之所以称作是回溯法，是因为在搜索的过程中需要回溯到问题的某个状态，所以这往往需要保存回溯时的一些状态属性。然而，分治法通常并不需要考虑回溯状态的保存。 分解问题的规模 分治法往往是将问题分解成若干个子问题的形式，然而回溯法往往是将问题分解成规模更小的一个子问题。由于分治法将问题分解成若干个子问题，故当前问题的解需要依赖于若干个子问题，也就是若干个搜索路径的解，所以重点在于如何合并子问题的解；而然回溯法问题规模就为1个，当前的搜索路径的问题触碰到边界条件时，即可得到当前搜索路径的问题的解，并不需要合并，或者说合并很简单。 分治法可变成复杂的回溯法 如果分治法保留了每个问题的可回溯的状态，并利用了这些状态，尽管这非常的不容易实现，因为某个问题的回溯的状态可能需要依赖很多其子问题的状态。如果成功保存了这些回溯状态，那么这个时候，分治法就成了复杂的回溯法。]]></description>
		
					<wfw:commentRss>https://blog.ihuxu.com/thoughts-on-divide-and-conquer-and-backtracking/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>一只青蛙跳出来的分治法、回溯法与动态规划</title>
		<link>https://blog.ihuxu.com/divide-and-conquer-backtracking-and-dynamic-programming-from-a-frog-jumping-out/</link>
					<comments>https://blog.ihuxu.com/divide-and-conquer-backtracking-and-dynamic-programming-from-a-frog-jumping-out/#comments</comments>
		
		<dc:creator><![CDATA[HU Xiaoxu]]></dc:creator>
		<pubDate>Fri, 28 Dec 2018 07:40:53 +0000</pubDate>
				<category><![CDATA[Basic Algorithm]]></category>
		<category><![CDATA[Computer Science]]></category>
		<category><![CDATA[Data Structure and Algorithm]]></category>
		<category><![CDATA[Dynamic Programming]]></category>
		<category><![CDATA[Back Tracking]]></category>
		<category><![CDATA[Divide and Conquer]]></category>
		<category><![CDATA[Original]]></category>
		<guid isPermaLink="false">http://blog.ihuxu.com/?p=9925</guid>

					<description><![CDATA[从2018年7月份开始，基础薄弱的我从0开始刷LeetCode题目。目的性很明确，也很简单——就是为了提高解决问题的思考实践能力，也为了提升自己的核心竞争力。也许，牛人会觉得这并不算什么竞争力。是的，我同意的。但，这是我目前能做的比较基础的事情罢了。 迄今（2018年12月28日）为止，已经刷了108道题目。顺序基本上是按照出现的频率（Frequency）来刷的，这个频率在LeetCode上需要订阅后才可以看得到。那么在刷了108道题目后，有那么一些题目会觉得“似曾相识”了，也会有一种触类旁通的感觉了。所以，我觉得应该适当放慢刷题的速度，同时做做总结了。 所以，计划了一项视频解说计划，在YouTubeh和B站都建立了《小旭解说算法之路》的频道，欢迎订阅，多多提建议。 那么，进入正题。经过了108道题的历练之后，我来说说对于分治法、回溯法和动态规划的理解。 我觉得他们三者是一个相互有交集的概念，并不是相互完全独立的。至于为什么不是完全独立的，在分别说说这三种方法的解决思路后，我们再终结一下。 分治法（Divide and Conquer） 分治法是解决规模庞大的问题的很好的思路，他通过降低问题的规模，形成若干个规模更小但形式相同的子问题，进行递归求解。在求解过后，将各个子问题的解合并起来，形成原问题的解。 那么它的大致流程主要分成三步： 所以，明确了三步之后，还要明确一件事件——实现方式：递归法。 分治法一般来说会采用递归法来进行实现，当然，利用迭代法（比如for、while）也是可以的。 所以，我们往往看到的递归算法从广义上来说都是分治法。无非就是有些递归算法将问题分解了若干个子问题，然而有些递归算法将问题分解成了一个子问题。那么有些作者会称作前者是分治法，后者是减治法。 其实，这个概念真的非常非常重要。在面对很多问题的时候，都可以用这种思路去思考。那么其中思考的一个非常重要的一点就是递归算法中的边界（跳出）条件的判定。 只要，我们想明白了求解子问题过程中的边界条件，那么问题就会很清晰，并且很容易写出程序来。否则，模糊的边界条件，会导致整个递归算法进入到“死循环”的尴尬地步。 举个例子 青蛙🐸跳台阶的问题：一只青蛙一次可以跳上1级台阶，也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法？ 那么如果我们用分治法的思路思考的话，这道题真是非常非常容易理解。 首先，当青蛙在面对第一个台阶时，他只有两种选择——跳一步还是跳两步。如果我们定义f(n)代表青蛙跳跃到n层台阶一共的方法数，那么我们可以将问题进行分解两个规模更小，但形式相同的问题： 其中f(n &#8211; 1)是青蛙选择跳一步后，剩下的子问题，同理f(n &#8211; 2)是青蛙选择跳两步后剩下的子问题。这样，我们就把问题进行了分解。 下面再谈谈如何解决，正如上面谈到的解决步骤，如果规模足够小那么直接返回，否则继续降低规模进行递归求解。这时，就是我们要确定边界条件——即当n = 1 和n = 2时的情况。 在明确了边角条件后，合并就非常的简单，也就是简单的相加即可了。 那么代码写出来是什么样子呢？ 回溯法（Backtracking） 回溯法，我理解应该也可以叫做深度优先搜索（Depth-First Search）。所以，他是一种搜索算法。 既然谈到搜索，往往这里面会面临选择的情景。以那个青蛙为例，当面对第一个台阶时，他有两个选择。当他选择一种选择后，将“义无反顾”的一条道走下去，每层都会进行一次选择，直到走到地n层位置时。这时，青蛙已经触碰到了边界，并得到了一种方案，之后青蛙会返回到最近的上一次选择时的情景，选择第二种情况继续走下去。以此往复，直到搜索全部的情景。 是的，这非常的抽象。我们来看看用二叉树来描述运动轨迹是怎么样的。我们假设n = 3。 颜色 左右子树 回溯 如下图中红框标记的位置就是回溯到某一个情况。 如果你理解了下图的运动轨迹，我想差不多对于回溯的搜索过程就基本了解了。所以，你可以找到其他回溯点么？ 理解了上图的运动轨迹后，那么，代码是什么样子呢？ 边界条件 再说更重要的选择的两个基本点 以此进行递归搜索（深度优先搜索DFS），在搜索到边界时进行回溯，以此往复直到搜索到所有情况为止。 动态规划（Dynamic Programming） 动态规划有两个重要的基本性质 最优子结构 如果一个问题的最优解包含了其中子问题的最优解，那么称其具有最优子结构的性质。 什么意思？青蛙在面对n个台阶时的解决方案数是f(n)，那么我们知道f(n) = f(n &#8211; 1) + f(n &#8211; 2)。其中的f(n &#8211; 1)与f(n &#8211; 2)就是两个子问题的最优解，此时我们可以理解成一个问题的最优解包含了其子问题的最优解，那么这个时候这种问题具有了最优子结构性质。 重叠子问题 这个性质，在我理解是对于上文提到的子问题的补充说明。当解决一个问题时，往往需要依赖于其更小规模的子问题的解，甚至是同时依赖于若干个规模更小的子问题的解，即子问题是被（重复）包含于比其更大的问题中的，所以他是具有重叠子问题的性质。 在这里，多提出一句，这个子问题是在解决当前问题时需要依赖的。即，只有计算了子问题，父问题才可能被求解。这是和贪心算法的重要区别所在。 状态转移方程<div class="read-more"><a class="btn read-more-btn" href="https://blog.ihuxu.com/divide-and-conquer-backtracking-and-dynamic-programming-from-a-frog-jumping-out/">Read More</a></div>]]></description>
		
					<wfw:commentRss>https://blog.ihuxu.com/divide-and-conquer-backtracking-and-dynamic-programming-from-a-frog-jumping-out/feed/</wfw:commentRss>
			<slash:comments>5</slash:comments>
		
		
			</item>
		<item>
		<title>我对彩色建模的理解（UML with Color）</title>
		<link>https://blog.ihuxu.com/my-understanding-of-color-modeling-uml-with-color/</link>
					<comments>https://blog.ihuxu.com/my-understanding-of-color-modeling-uml-with-color/#respond</comments>
		
		<dc:creator><![CDATA[HU Xiaoxu]]></dc:creator>
		<pubDate>Wed, 24 Oct 2018 08:54:55 +0000</pubDate>
				<category><![CDATA[Computer Science]]></category>
		<category><![CDATA[System Design]]></category>
		<category><![CDATA[Original]]></category>
		<category><![CDATA[UML]]></category>
		<guid isPermaLink="false">http://blog.ihuxu.com/?p=9849</guid>

					<description><![CDATA[使劲戳这个PDF =&#62; 彩色建模（Color With UML）]]></description>
		
					<wfw:commentRss>https://blog.ihuxu.com/my-understanding-of-color-modeling-uml-with-color/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>最大流问题之 Ford-Fulkerson 算法</title>
		<link>https://blog.ihuxu.com/maximum_flow_problem_of_graph_ford_fulkerson_algorithm/</link>
					<comments>https://blog.ihuxu.com/maximum_flow_problem_of_graph_ford_fulkerson_algorithm/#respond</comments>
		
		<dc:creator><![CDATA[HU Xiaoxu]]></dc:creator>
		<pubDate>Thu, 18 Oct 2018 01:17:25 +0000</pubDate>
				<category><![CDATA[Computer Science]]></category>
		<category><![CDATA[Data Structure and Algorithm]]></category>
		<category><![CDATA[Graph]]></category>
		<category><![CDATA[Maximum Flow]]></category>
		<category><![CDATA[Original]]></category>
		<category><![CDATA[Python]]></category>
		<guid isPermaLink="false">http://blog.ihuxu.com/?p=9844</guid>

					<description><![CDATA[Ford-Fulkerson算法（亦即标号法？）的输入与步骤如下： 输入 给定一个容量为c的图G=(V, E)，源点s与汇点（终点）t 步骤 对图G中每一个边(u, v)的流量f(u, v)进行初始化为0 查询过程：寻找（DFS、深度优先搜索方式）图G中的一条路径p，其中每一条边(u, v) ∈p，都有fc(u, v) = c(u, v) &#8211; f(u, v) &#62; 0（c(u, v) 代表当前边的容量，f(u, v) 代表当前边已有的流量，即c(u, v) &#8211; f(u, v)代表当前边可用的最大流量，即剩余流量） 调整过程：计算当前路径下每条边的最小剩余容量，cf(p) = min{fc(u, v) : (u, v) ∈p}，然后对于每条边进行如下操作： f(u, v) = f(u, v) + cf(p) （前向狐） f(v, u) = f(v, u) &#8211; cf(p) （后向狐） 往复上述2与3步骤，直至无法找到路径p为止]]></description>
		
					<wfw:commentRss>https://blog.ihuxu.com/maximum_flow_problem_of_graph_ford_fulkerson_algorithm/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>滴滴出行业务平台研发岗位内推</title>
		<link>https://blog.ihuxu.com/didichuxing-rd-positions/</link>
					<comments>https://blog.ihuxu.com/didichuxing-rd-positions/#comments</comments>
		
		<dc:creator><![CDATA[HU Xiaoxu]]></dc:creator>
		<pubDate>Fri, 25 May 2018 02:43:23 +0000</pubDate>
				<category><![CDATA[Job Interview]]></category>
		<category><![CDATA[Job Opportunity]]></category>
		<category><![CDATA[Original]]></category>
		<guid isPermaLink="false">http://blog.ihuxu.com/?p=9750</guid>

					<description><![CDATA[有意者欢迎骚扰:huxu@didichuxing.com 更新于：2018.05.25 15:55 【在线业务研发工程师(PHP/Golang)】 我们需要一个这要的你： 有志于参与一场出行行业的变革； 对于大流量高并发业务场景的技术挑战心潮澎湃。 用你的代码影响成千上万人： 负责快车、专车、拼车、优步、优享、出租车等核心业务的服务端研发工作； 负责接送机、站点拼车、跨城、小巴等垂直出行场景的服务建设和通勤、休娱、商旅等新出行场景孵化。 【中台建设&#38;中间件研发工程师/架构师】 众里寻你千百度： 每一次将复杂世界变得简单都让你心花怒放； 每一次你的系统都能云淡风轻跨越一座座流量洪峰，而你依然心若止水。 你来协助我们提升生产力： 负责打磨现有产品业务流程，深入了解司乘两端业务，对出行场景进行抽象优化； 负责出行中台&#38;中间件架构设计和优化工作，提供新业务的快速扩展和接入能力。 有意者欢迎骚扰:huxu@didichuxing.com 更新于：2018.05.25 11:00]]></description>
		
					<wfw:commentRss>https://blog.ihuxu.com/didichuxing-rd-positions/feed/</wfw:commentRss>
			<slash:comments>4</slash:comments>
		
		
			</item>
		<item>
		<title>[维护中]基于文本图形（ncurses）的文本搜索工具 ncgrep</title>
		<link>https://blog.ihuxu.com/ncgrep-based-on-ncurses-global-regular-search-tool/</link>
					<comments>https://blog.ihuxu.com/ncgrep-based-on-ncurses-global-regular-search-tool/#comments</comments>
		
		<dc:creator><![CDATA[HU Xiaoxu]]></dc:creator>
		<pubDate>Tue, 05 Dec 2017 09:21:51 +0000</pubDate>
				<category><![CDATA[Computer Science]]></category>
		<category><![CDATA[Middleware]]></category>
		<category><![CDATA[Others]]></category>
		<category><![CDATA[NCGREP]]></category>
		<category><![CDATA[NCURSES]]></category>
		<category><![CDATA[Original]]></category>
		<category><![CDATA[Utilities]]></category>
		<guid isPermaLink="false">http://blog.ihuxu.com/?p=9649</guid>

					<description><![CDATA[源码下载&#160;http://github.com/ncgrep/ncgrep 背景 作为一个 VIM 党，日常工作开发中，会经常利用 grep 进行关键词搜索，以快速定位到文件。如图： 但是，这一过程会有两个效率问题： 可想而知，当搜索的内容结果集比较大时，可谓痛苦。 那可以用 Vim 中的 Ag 插件进行搜索啊？ 是的，但他只解决了交互的问题。仍然没有解决结果集分组分类的痛点。 思路 在使用 Eclipse 等 IDE 进行文本全局搜索时，在加载效果（懒加载）可视化方面有很大优势。 &#160; 那么，期望基于 linux 系统，提供一个类似的搜索工具。优点（功能）如下： 基于文本图形界面的类库是什么呢？网上大致了解了下 VIM、htop 类似的软件，其都是基于一个叫 ncurses 的类库实现的。 项目 项目的名称：ncgrep 为什么？因为有 ngrep、egrep 等。(注：ncgrep 没有引用 grep 源码） 项目的 Demo 代码 http://github.com/ncgrep/ncgrep 类似项目 NGP youtube -&#62;&#160;https://www.youtube.com/watch?v=MesYBY8271s 总结 工具为效率而生，期望能够带来收益。]]></description>
		
					<wfw:commentRss>https://blog.ihuxu.com/ncgrep-based-on-ncurses-global-regular-search-tool/feed/</wfw:commentRss>
			<slash:comments>3</slash:comments>
		
		
			</item>
		<item>
		<title>[开发中]基于树莓派的智能家居项目的设想与实现 Hestia</title>
		<link>https://blog.ihuxu.com/tentative-plan-and-realization-of-smart-home-project-hestia-based-on-raspberry-pi/</link>
					<comments>https://blog.ihuxu.com/tentative-plan-and-realization-of-smart-home-project-hestia-based-on-raspberry-pi/#comments</comments>
		
		<dc:creator><![CDATA[HU Xiaoxu]]></dc:creator>
		<pubDate>Wed, 22 Nov 2017 06:07:26 +0000</pubDate>
				<category><![CDATA[Computer Science]]></category>
		<category><![CDATA[Middleware]]></category>
		<category><![CDATA[Others]]></category>
		<category><![CDATA[Original]]></category>
		<category><![CDATA[Raspberry Pi]]></category>
		<guid isPermaLink="false">http://blog.ihuxu.com/?p=9642</guid>

					<description><![CDATA[注：本文内容的准确性仅限于笔者写该篇文章时的情况，不保证后续与实际项目代码一致。实时内容还请关注 Github 项目托管页面：https://github.com/GenialX/hestia-server 树莓派，一个五脏俱全，集几乎所有功能于一身的微型计算器。大约一两月之前，屈屈 300 百大洋收入囊中。 入手之后，出于对自动化的兴趣，慢慢地研究如何实现室内家电的智能自动化控制。在断断续续地，不断地摸索之后，有了若干想实现的点子，迄今为止也有所实践。 点子 方案 硬件 首先，除了树莓派之外，还需要如下硬件： 软件 此外，本案例同样需要如下软件环境的支持（注：如果您完全不懂软件，且不愿意为实现本案例的结果而学习软件知识，那么下面的需要软件知识的相关内容可以不用深究）： 架构 系统大致分为三部分 各部分的主要用途 项目 Hestia Server&#160;https://github.com/GenialX/hestia-server Hestia RPi&#160;https://github.com/GenialX/hestia-rpi Hestia Android&#160;https://github.com/GenialX/hestia-android Hestia iOS&#160;https://github.com/GenialX/hestia-ios 实现功能 总结 未完待续&#8230; 历史 相关文章：Android O后台持续获取地理位置的简单调研过程]]></description>
		
					<wfw:commentRss>https://blog.ihuxu.com/tentative-plan-and-realization-of-smart-home-project-hestia-based-on-raspberry-pi/feed/</wfw:commentRss>
			<slash:comments>3</slash:comments>
		
		
			</item>
		<item>
		<title>利用内网穿透 frp 工具实现外网链接（ssh）内网树莓派设备</title>
		<link>https://blog.ihuxu.com/the-use-of-intranet-through-frp-tools-to-achieve-external-network-access-to-the-network-raspberry-equipment/</link>
					<comments>https://blog.ihuxu.com/the-use-of-intranet-through-frp-tools-to-achieve-external-network-access-to-the-network-raspberry-equipment/#respond</comments>
		
		<dc:creator><![CDATA[HU Xiaoxu]]></dc:creator>
		<pubDate>Tue, 17 Oct 2017 04:50:03 +0000</pubDate>
				<category><![CDATA[Computer Science]]></category>
		<category><![CDATA[Dev Tool]]></category>
		<category><![CDATA[Others]]></category>
		<category><![CDATA[FRP]]></category>
		<category><![CDATA[Original]]></category>
		<category><![CDATA[Raspberry Pi]]></category>
		<category><![CDATA[SSH]]></category>
		<guid isPermaLink="false">http://blog.ihuxu.com/?p=9628</guid>

					<description><![CDATA[内网穿透原理 内网穿透（Net 穿透）也即端口映射，笔者粗暴理解是一种能够将外网机器与内网机器（外网无法直接访问的设备）建立通信的一种技术解决方案。 百度百科 尽管有许多穿越 NAT 的技术，但没有一项是完美的，这是因为 NAT 的行为是非标准化的。这些技术中的大多数都要求有一个公共服务器，而且这个服务器使用的是一个众所周知的、从全球任何地方都能访问得到的 IP 地址。一些方法仅在建立连接时需要使用这个服务器，而其它的方法则通过这个服务器中继所有的数据 —— 这就引入了带宽开销的问题。 具体原理详见百度百科=&#62;&#160;https://baike.baidu.com/item/NAT%E7%A9%BF%E8%B6%8A 需要资源 一台公网服务器（可以通过 IP 直接访问） 树莓派（也可以是电脑，以树莓派为例） 安装 本文以 frp v 0.13.0 为例（具体版本可以自己定，但不保证其他版本能够成功）。 笔者在 go 1.7.4 版本下编译 frp v 0.13.0 时会出现如下编译错误，根据 frp 作者留言，改用 go 1.8.3 版本编译。 *ht.Server has no field or method Close() 安装 golang 环境 由于 frp 工具是基于 golang 编写，所以需要安装 golang 环境。 以 go1.8.3 版本为例（亲测有效） 由于下载的是编译好的包，所以安装很简单。下载后，进行解压，并设置一些环节变量即可。 具体安装步骤详见：https://golang.org/doc/install 安装 frp 工具 启动 &#38; 使用 frp工具 使用起来很简单，只需要简单修改配置文件后，执行启动命令即可。 具体步骤详见：https://github.com/fatedier/frp/blob/master/README_zh.md]]></description>
		
					<wfw:commentRss>https://blog.ihuxu.com/the-use-of-intranet-through-frp-tools-to-achieve-external-network-access-to-the-network-raspberry-equipment/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>ZigZag Conversion(math)</title>
		<link>https://blog.ihuxu.com/zigzag-conversion-math/</link>
					<comments>https://blog.ihuxu.com/zigzag-conversion-math/#respond</comments>
		
		<dc:creator><![CDATA[HU Xiaoxu]]></dc:creator>
		<pubDate>Thu, 31 Aug 2017 15:52:40 +0000</pubDate>
				<category><![CDATA[Computer Science]]></category>
		<category><![CDATA[Data Structure and Algorithm]]></category>
		<category><![CDATA[LeetCode]]></category>
		<category><![CDATA[Math]]></category>
		<category><![CDATA[Original]]></category>
		<guid isPermaLink="false">http://blog.ihuxu.com/?p=9594</guid>

					<description><![CDATA[Question The string&#160;"PAYPALISHIRING"&#160;is written in a zigzag pattern on a given number of rows like this: (you may want to display this pattern in a fixed font for better legibility) P A H N A P L S I I G Y I R And then read line by line:&#160;"PAHNAPLSIIGYIR"Write the code that will take a string and make this conversion given a number of rows: string convert(string text, int<div class="read-more"><a class="btn read-more-btn" href="https://blog.ihuxu.com/zigzag-conversion-math/">Read More</a></div>]]></description>
		
					<wfw:commentRss>https://blog.ihuxu.com/zigzag-conversion-math/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>PHP Internals Book 中文版 &#8211; Zvals &#8211; 基础结构</title>
		<link>https://blog.ihuxu.com/php-internals-book-in-chinese-zvals-basic-structure/</link>
					<comments>https://blog.ihuxu.com/php-internals-book-in-chinese-zvals-basic-structure/#respond</comments>
		
		<dc:creator><![CDATA[HU Xiaoxu]]></dc:creator>
		<pubDate>Wed, 08 Mar 2017 11:28:50 +0000</pubDate>
				<category><![CDATA[C/C++]]></category>
		<category><![CDATA[Computer Language]]></category>
		<category><![CDATA[Computer Science]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Original]]></category>
		<category><![CDATA[ZEND]]></category>
		<category><![CDATA[ZVAL]]></category>
		<guid isPermaLink="false">http://blog.ihuxu.com/?p=9488</guid>

					<description><![CDATA[基础结构 一个 zval（“Zend value”的缩写）代表一个任意类型的 PHP 变量。所以，它很可能是 PHP 中最重要的数据结构，同时你将会频繁地使用它。本章节讲述zvals的基础概念及其使用方法。 类型和值 每一个 zval 都会存储某个值和其对应的类型。这点非常重要，因为 PHP 是一门动态类型语言，所以变量的类型只有当运行时才会确定，并不是在编译时就能够确定。此外，zval 的类型在其生命周期是可以改变的，所以如果这个 zval 在最初存储了一个整形，那么在之后的某个时间点他也可能会存储了一个字符串。 类型是存储在一个整形的标签中（一个 unsigned char 类型的变量）。它有 8 中类型的值，分别对应着 PHP 中的 8 中变量类型。这些值可以用诸如 IS_TYPE 形式的常量来使用。比如：IS_NULL 对应 null 类型，IS_STRING 对应字符串类型。 真实的值是存储在一个联合体中，如下所示： 写给那些不了解联合体概念的同学：一个联合体定义了多个不同类型的成员，但是在某一刻只能使用其中一个成员。比如：如果给 value.lval 成员赋值了，那么你就需要用 value.lval 的方式来访问这个值，而不能用其他成员（否则会侵犯“strict aliasing”规则，并导致未定义的行为 &#8211; undefined behaviour）。这是因为联合体将其所有成员存储再一个相同的内存地址中，并根据访问的是哪一个成员来访问值。联合体的大小由其中的最大的成员决定。 在使用 zvals 时，类型标签用来寻找正在使用的是联合体中的哪一个成员。在介绍一些相关的 APIs 之前，我们先来大致过一下 PHP 支持的不同类型及其存储方式。 最简单的类型是 IS_NULL：事实上不需要存储任何值，因为它本身就保留一个 null 值。 为了存储数字，PHP 提供了 IS_LONG 和 IS_DOUBLE 类型，它们分别用于表达 long lval 和 double dval 两种成员。前者用于存储整形，然而后者用于存储浮点型数字。 针对于 long 类型有一些应该注意的事情：首先，这是一个有符号的整形类型，比如：他可以存储正数和负数，但是通常来说不适用于做一些位操作。第二，long 类型在不同的平台上有不同的大小：在<div class="read-more"><a class="btn read-more-btn" href="https://blog.ihuxu.com/php-internals-book-in-chinese-zvals-basic-structure/">Read More</a></div>]]></description>
		
					<wfw:commentRss>https://blog.ihuxu.com/php-internals-book-in-chinese-zvals-basic-structure/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>PHP Internals Book 中文版 &#8211; Zvals</title>
		<link>https://blog.ihuxu.com/php-internals-book-in-chinese-zvals/</link>
					<comments>https://blog.ihuxu.com/php-internals-book-in-chinese-zvals/#respond</comments>
		
		<dc:creator><![CDATA[HU Xiaoxu]]></dc:creator>
		<pubDate>Wed, 08 Mar 2017 11:26:54 +0000</pubDate>
				<category><![CDATA[C/C++]]></category>
		<category><![CDATA[Computer Language]]></category>
		<category><![CDATA[Computer Science]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Original]]></category>
		<category><![CDATA[ZEND]]></category>
		<guid isPermaLink="false">http://blog.ihuxu.com/?p=9487</guid>

					<description><![CDATA[Zvals 本章节的主题为用来表达 PHP 变量的 zval 数据结构。我们将会围绕 zvals 的概念和如何在扩展开发中使用两方面来进行阐述。 目录 基础结构 类型和值 访问宏 赋值 内存管理 值语义和引用语义 引用计数和写时复制 分配并初始化 zvals 管理引用计数和 zval 销毁 复制 zvals 分离 zvals 类型转换和操作符 基础操作符 比较 类型转换]]></description>
		
					<wfw:commentRss>https://blog.ihuxu.com/php-internals-book-in-chinese-zvals/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>PHP Internals Book 中文版</title>
		<link>https://blog.ihuxu.com/php-internals-book-in-chinese/</link>
					<comments>https://blog.ihuxu.com/php-internals-book-in-chinese/#respond</comments>
		
		<dc:creator><![CDATA[HU Xiaoxu]]></dc:creator>
		<pubDate>Tue, 07 Mar 2017 05:18:42 +0000</pubDate>
				<category><![CDATA[C/C++]]></category>
		<category><![CDATA[Computer Language]]></category>
		<category><![CDATA[Computer Science]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Original]]></category>
		<guid isPermaLink="false">http://blog.ihuxu.com/?p=9484</guid>

					<description><![CDATA[文章目录 Github（更新最快） 你看到的是 PHP 内核中文版，翻译自 PHP Internals Book。 为什么要翻译 对技术的饥渴 对英语的热爱 方便汉语作为母语的人学习交流 官方网站 PHP Internals Book Github（更新最快） https://github.com/huxiaoxu2019/php-internals-book-in-chinese 关于作者 Hu Xiaoxu 内容目录 Introduction Using the PHP build system Building PHP Building PHP extensions Creating PHP extensions Zvals Basic structure Memory management Casts and operations Implementing functions Hashtables Basic structure Hashtable API Symtable and array API Hash algorithm and collisions Classes and objects Simple classes Custom object storage Implementing typed arrays<div class="read-more"><a class="btn read-more-btn" href="https://blog.ihuxu.com/php-internals-book-in-chinese/">Read More</a></div>]]></description>
		
					<wfw:commentRss>https://blog.ihuxu.com/php-internals-book-in-chinese/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>工作效率之动态 IP 域名化篇</title>
		<link>https://blog.ihuxu.com/work-efficiency-dynamic-ip-to-domain-name/</link>
					<comments>https://blog.ihuxu.com/work-efficiency-dynamic-ip-to-domain-name/#respond</comments>
		
		<dc:creator><![CDATA[HU Xiaoxu]]></dc:creator>
		<pubDate>Mon, 13 Feb 2017 13:51:57 +0000</pubDate>
				<category><![CDATA[Computer Science]]></category>
		<category><![CDATA[Dev Tool]]></category>
		<category><![CDATA[Others]]></category>
		<category><![CDATA[DNS]]></category>
		<category><![CDATA[Launchd]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Mac]]></category>
		<category><![CDATA[Original]]></category>
		<guid isPermaLink="false">http://www.ihuxu.com/blog/?p=9460</guid>

					<description><![CDATA[在公司里，RD 们不免会使用一些代理服务来进行抓包操作。那么就需要获取代理服务器（一般为自己的电脑）的内网 IP。然而，这个内网 IP 并不是固定不变的。所以，每次配置代理 IP 时就略显麻烦。那么，下面就来聊聊如何解决这个尴尬，提升效率。 方案 将非固定 IP 实时解析到域名中。利用阿里云的域名解析开发者 API 进行定时的更新。其中的定时用本机（Mac）的 Launchd 实现（类似 Linux 下的 Crontab）。 原材料 步骤 下载阿里云 SDK &#38; 编写更新脚本 代码库：https://github.com/aliyun/aliyun-openapi-php-sdk.git 官方的接口文档：https://help.aliyun.com/document_detail/29774.html?spm=5176.doc29740.6.615.ADurH2 其中有个简要的文档，确实文档比较“简陋”，还会看到 github 中 issues 骂娘的。 在调用使用 SDK 编写脚本的过程中，会用到一个秘钥。这个秘钥可以到阿里云的管理控制台中获取。如下图： 配置 Mac 的 Timed Job 打开 Mac 终端，进入目录 /System/Library/LaunchDaemons 下。会看到很多 plist 为后缀的文件。每一个文件都是一个定时任务。具体的定时任务的写法，请参见苹果开发中中心文档：Scheduling Timed Jobs 结束语 这样一来，在任何情况下配置代理时填入一个固定的域名就搞定了。其实，除此之外还可以把一些有变动的或者不好记的IP都解析成域名，这样在使用时会顺手些。比如登陆一些开发机： 文章来源：工作效率之动态IP域名化篇]]></description>
		
					<wfw:commentRss>https://blog.ihuxu.com/work-efficiency-dynamic-ip-to-domain-name/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>小型网站架构降 Apache 与 MySQL 内存占用比率</title>
		<link>https://blog.ihuxu.com/how-to-configure-the-apache-and-mysql-server-effectively-under-the-framework-of-a-small-web-site/</link>
					<comments>https://blog.ihuxu.com/how-to-configure-the-apache-and-mysql-server-effectively-under-the-framework-of-a-small-web-site/#respond</comments>
		
		<dc:creator><![CDATA[HU Xiaoxu]]></dc:creator>
		<pubDate>Tue, 13 Dec 2016 11:38:12 +0000</pubDate>
				<category><![CDATA[Computer Science]]></category>
		<category><![CDATA[Dev Problem]]></category>
		<category><![CDATA[Apache]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Memory]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Original]]></category>
		<guid isPermaLink="false">http://www.ihuxu.com/blog/?p=9365</guid>

					<description><![CDATA[前言 这篇文章以我的阿里云服务器为例（你眼前的博客正是搭在这个服务器上），阐述下小型网站（Linux+Apache+MySQL+PHP）对于内存利用率提升的配置方法的一个点。 正文 我的服务器是阿里云的，在一年前由于数据库（MySQL）频繁内存不足宕机就“潇洒”地升级了配置到2G内存。所以，目前机器的配置如下： CPU： 1核 内存： 2048 MB 操作系统： CentOS 6.5 32位 公网IP： 115.28.36.19 带宽计费方式： 按固定带宽 当前使用带宽： 1Mbps 同时，正常使用情况下的内存使用情况如下： 图中显示 MySQL 占用 440m，Apache 占用 44m。当然，这是MySQL 服务和 Apache 服务刚刚重启后的情况。实际的内存占用会比这大，因为随着业务的进行，会进行 Cache 的累积，最后导致整体的使用内存增大。 下面分别调整 MySQL 和 Apache 的配置文件。 MySQL 修改 /etc/my.cnf 文件，增加如下配置内容： 内容使用情况如下： 如图所示，在修改 MySQL 配置项后内存使用已经大幅度下降到 71m 了。所以，默认的 MySQL 配置真是不适合我们这种小型网站。同时，你会注意到运行了一段时间后，Apache 内存占比上升，使用量达到406m。真是可怕。 下面我们修改 Apache 的配置文件，httpd.conf： 由于我的 Apache 加载的是 event 模式，所以我这里修改了相应的 event 模块配置。如果你想知道你自己加载的是哪种模式，每一个配置项是什么意思，那么你可以参阅下这篇文章：apache2.4.x 三种 MPM 介绍。 修改后配置重启就 OK 了。 总结 没有总结]]></description>
		
					<wfw:commentRss>https://blog.ihuxu.com/how-to-configure-the-apache-and-mysql-server-effectively-under-the-framework-of-a-small-web-site/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>在 Linux 下通过 strace 与 lsof 命令排查 PHP 异常进程</title>
		<link>https://blog.ihuxu.com/php-abnormal-process-investigation/</link>
					<comments>https://blog.ihuxu.com/php-abnormal-process-investigation/#respond</comments>
		
		<dc:creator><![CDATA[HU Xiaoxu]]></dc:creator>
		<pubDate>Wed, 30 Nov 2016 03:02:51 +0000</pubDate>
				<category><![CDATA[Computer Language]]></category>
		<category><![CDATA[Computer Science]]></category>
		<category><![CDATA[Dev Problem]]></category>
		<category><![CDATA[Foundation]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Operation System]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Original]]></category>
		<guid isPermaLink="false">http://www.ihuxu.com/blog/?p=9350</guid>

					<description><![CDATA[在有些时候，会遇到 PHP 进程异常卡死的情况。面对这种情况，首先考虑到的就是分析代码进行优化改进，或者重启进程。但是，这种方式来排查不一定能找到根本原因。因为有些时候异常 PHP 进程卡死的原因可能是非常奇葩的问题，比如外部资源异常如 DB、Redis 或第三方 API 等。上一次关于超级话题签到提醒定时任务 PHP 进程异常的处理，问题竟然出现在外部的 DB 的链接上。由于网络原因导致读取 DB 没有响应卡死。 这一次情况比较严重，超级话题积分系统的计算有一部分是通过 Trigger（类似队列）接受全站数据进行积分计算与入库。由于用户反馈问题，来到队列机查看进程情况。如下： 之后，我们查看某个进程的处理日志。如下： 发现进程（pid 10693）在重启之后卡主。 于是利用 strace 查看进程处理过程： 如 strace 信息可以看出，该异常 PHP 进程一直在循环的读取，貌似进入死循环： 接着利用 lsof 来查看该进程的所有链接资源，如下： 所以，可以看出该 PHP 异常进程是在不断的读取 FD 值为 4u 对应的资源，该资源正式 trigger 的服务资源。 通过上述的判断，可以初步断定出现在 trigger 服务上，接着就是找相关部门的人继续深入排查了。 注：已处理敏感信息，如有问题请及时联系站长。]]></description>
		
					<wfw:commentRss>https://blog.ihuxu.com/php-abnormal-process-investigation/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>自从有了她，再也不怕断签了：超级话题签到提醒</title>
		<link>https://blog.ihuxu.com/check-in-push-for-super-topic-at-weibo/</link>
					<comments>https://blog.ihuxu.com/check-in-push-for-super-topic-at-weibo/#respond</comments>
		
		<dc:creator><![CDATA[HU Xiaoxu]]></dc:creator>
		<pubDate>Tue, 25 Oct 2016 06:24:37 +0000</pubDate>
				<category><![CDATA[Computer Language]]></category>
		<category><![CDATA[Computer Science]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Technical Summary]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Original]]></category>
		<guid isPermaLink="false">http://www.ihuxu.com/blog/?p=7394</guid>

					<description><![CDATA[前言 在解决了上一次关于超级话题积分bug后，又接到超级话题签到提醒的产品需求。这是一篇偏于技术实现的文章，讲述的比较笼统，业务围绕超级话题的签到提醒进行展开。如果，您对超级话题签到提醒的技术背景与实现感兴趣，那么这篇文章希望对你有帮助。 当然，如果你是某个超级话题的超级粉丝，比如鹿晗，张艺兴，但是发现断签了。那么我非常替你感到“痛心”，因为目前超级话题没有补签功能。当然，如果你觉得是因为系统问题导致没有连续签到，那么你可以通过超级话题的官方反馈方式进行反馈来解决问题。当然，我劝你这么做之前一定要三思。因为，通过我排查的经验而言，基本山是由于你们（用户）把时间搞错了，而导致没有续签。而且，目前的签到提醒功能会在每天晚上提醒你签到的哦~ 产品 最近，在忙活超级话题的签到提醒产品的开发。首先，这是第一次比较热切的关注用户反应的产品。虽然说，对于产品的参与和认知并没有多么深入的理解，但是愈发的觉得这件事很有意识，也更想参与其中。 超级话题打破了传统话题的模式，以社区的形式展现，提高用户互动与粘性。其中，签到是不可或缺的一项功能。然而在前期，签到功能在给用户带来了高回访的情况下，也有着苦恼。作为研发同学，更是备受折磨。为什么？产品总是拿着反馈中自称经签过但却莫名断签的用户ID找我排查问题所在。然而，几乎都是一些凌晨时分签到而次日未签的情形。尽管是这样，用户的反感也是无法消除的。 为了不再做反复的排查劳动，只好做了一个相关查询后台。 产品同学为了召回用户，提供话题的UV和PV，提出了签到提醒的概念。 签到提醒会根据当前用户的签到行为，进行提醒私信的推送。目前为止，基本上每日需要提醒的量大约在85w左右。然而，在发送私信的过程中并非如此顺利。 技术 首先，要进行数据的准备。利用crontab定时将DB中的数据写入磁盘文件。之所以这么做，主要是由于DB中的数据是动态的，需要将数据写成静态的形式以更好的分批处理。 然仍采用crontab定时启动发送私信的脚本。将启动n个进程，同时处理上述步骤生成的n个文件。以curl_multi的方式批量调用话题粉丝服务的内部接口。 数据 超级话题提醒私信下发量：85W/日 超级话题提醒倒流UV：可观 下面的Redis服务中Key的曲线图，可以约等于下发的私信量： 问题 在形成上面的技术流程之前，也是经过了几番周折。 最初，以单进程的方式直接从DB读取数据，单次调用粉丝服务的接口进行发送私信。然而，在这种情况下，每日（2.5个小时）却只能发送5-6w的私信量。 由于压力主要在外部粉丝服务接口上，所以采取了批量调用的方式。利用PHP中的curl_multi，逢10批量调用粉丝服务接口。这样下来，每日（5.5个小时）能发送51w左右的私信。 然而，还是不能满足近100w的私信调用量。所以，增加了数据准备阶段。将数据写成静态文件，以多个进程的形式，同时处理文件以批量调用粉丝服务接口来发送私信。 在功能上线的第一天晚间，观察处理文件的进程“卡死”。 从上面两图可以确定，PHP进程卡死的原因在于读取MySQL服务中。进过排查处理后，程序得以进入正常流程。 目前为止，每日的调用量完全可以满足所需要发送的私信量。 用户 用户对签到提醒的反馈还是非常不错的，有图为证： 总结 针对于这种需要长时间运行与调用外部资源的脚本，最重要的就行要进行好完善的异常处理机制。由于PHP脚本的异常处理并非强制的，如果处理不妥到，会导致进程直接终止，排查起来也很困难。 同时，对于相关资源的监控也很重要。比如，当前机器的CPU资源，接口的平均响应时间，DB服务的相应时间等等。以确定每次执行期间相关资源的健康状态。]]></description>
		
					<wfw:commentRss>https://blog.ihuxu.com/check-in-push-for-super-topic-at-weibo/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>PHP 的 Traits：到底是祸害还是好得飞起？</title>
		<link>https://blog.ihuxu.com/php-traits-good-or-bad/</link>
					<comments>https://blog.ihuxu.com/php-traits-good-or-bad/#respond</comments>
		
		<dc:creator><![CDATA[HU Xiaoxu]]></dc:creator>
		<pubDate>Wed, 12 Oct 2016 11:31:27 +0000</pubDate>
				<category><![CDATA[Computer Language]]></category>
		<category><![CDATA[Computer Science]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Original]]></category>
		<category><![CDATA[Traits]]></category>
		<guid isPermaLink="false">http://www.ihuxu.com/blog/?p=6479</guid>

					<description><![CDATA[在 2012 年 3 月初，PHP 团队宣布了 5.4 版本的发布。程序员们对这次的发布已期待许久，因为这一次的升级带来了很多特性的加入。其中，最受追捧的是 Traits。为了构建这次发布的版本，Shammer C 特意为此撰写了一篇文档：如何使用 PHP 的 Traits，我强烈的建议您在读这篇文章之前拜读一下，因为这篇文章需要读者能够对 Traits 有一定的基础了解。 Traits 已经被 PHP 社区广泛的接受，最为关键的是因为它包含了其他 Java、C++ 和 Python 编程语言的特性。除此之外，Traits 也被广大的网友们神化了。那些程序员狂砍这种特性将给他们的项目带来多么大的益处，尤其指出它是能够替代面向对象（OOP）继承的特性。然而，Traits 真的有那么神奇么？难道真的能对 PHP 开发有所促进么？还是败絮其中呢？ PHP 的 Traits 是个祸害 从表面上来看，由于它可以降低整个应用中代码的复用成本而受到了非常强烈的支持。此外，它仍然可以帮你提高代码的可维护性，并看起来更简洁。 尽管 Traits 是那么的受欢迎，但是许多高级程序员却担心将来的情况并不会像当初设计的那样。高级程序员 Anthony Ferrara 担心它将会变成下一代被滥用的功能，像 evel 和 constants 那样。但在此之前，Anthony 曾提出了一个有趣的观点：Traits 其实是一个没有 state 的 Mixins 的具体集合。PHP 中的 Traints 支持 state 的使用。所以，PHP 的 Traints 实际就是 Mixins。这个简单的观点说明了 PHP Traits 的最终真实的意图，其实就是“挂着羊皮卖狗肉”。更不用解释为什么会以 Mixins 的形式，而不是以全球公认的无 state 的 Mixins 形式来处理（很抱歉，我都没明白是啥意思，看来还得深入了解下）。 Anthony 继续讲到，使用 Traints<div class="read-more"><a class="btn read-more-btn" href="https://blog.ihuxu.com/php-traits-good-or-bad/">Read More</a></div>]]></description>
		
					<wfw:commentRss>https://blog.ihuxu.com/php-traits-good-or-bad/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>深入 MySQL 用户自定义变量：使用详解及其使用场景案例</title>
		<link>https://blog.ihuxu.com/explaination-of-the-mysql-variables-usage-and-the-use-case/</link>
					<comments>https://blog.ihuxu.com/explaination-of-the-mysql-variables-usage-and-the-use-case/#comments</comments>
		
		<dc:creator><![CDATA[HU Xiaoxu]]></dc:creator>
		<pubDate>Tue, 04 Oct 2016 02:21:09 +0000</pubDate>
				<category><![CDATA[Computer Science]]></category>
		<category><![CDATA[Middleware]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Original]]></category>
		<guid isPermaLink="false">http://www.ihuxu.com/blog/?p=5879</guid>

					<description><![CDATA[一、前言 在前段工作中，曾几次收到超级话题积分漏记的用户反馈。通过源码的阅读分析后，发现问题出在高并发分布式场景下的计数器上。计数器的值会影响用户当前行为所获得积分的大小。比如，当用户在某超级话题下连续第 n（n 即计数器的值）次进行转发帖子时，将会获得与 n 相关的分数。然而，在第一次改进后问题依然存在。所以，这次在之前的基础上，通过使用 MySQL 变量的途径来解决该问题。 二、到底 MySQL 的变量分哪几类？ MySQL变量一共分为两大类：用户自定义变量和系统变量。如下： 本文涉及的内容为用户自定义会话变量，若对其他分类无感，请点击这里。 PS：用户定义的会话变量和系统定义的会话变量有什么区别？ 局部变量 局部变量一般用于 SQL 的语句块中，比如存储过程中的 begin 和 end 语句块。其作用域仅限于该语句块内。生命周期也仅限于该存储过程的调用期间。 上述存储过程中定义的变量 c 就是局部变量。 会话变量 会话变量即为服务器为每个客户端连接维护的变量。在客户端连接时，使用相应全局变量的当前值对客户端的回话变量进行初始化。设置会话变量不需要特殊权限，但客户端只能更改自己的会话变量。其作用域与生命周期均限于当前客户端连接。 会话变量的赋值： 会话变量的查询： 全局变量 全局变量影响服务器整体操作。当服务器启动时，它将所有全局变量初始化为默认值。这些默认值可以在选项文件中或在命令行中指定的选项进行更改。要想更改全局变量，必须具有 SUPER 权限。全局变量作用于 server 的整个生命周期，但是不能跨重启。即重启后所有设置的全局变量均失效。要想让全局变量重启后继续生效，需要更改相应的配置文件。 全局变量的设置： 全局变量的查询： 三、MySQL用户自定义变量详解 你可以利用 SQL 语句将值存储在用户自定义变量中，然后再利用另一条 SQL 语句来查询用户自定义变量。这样以来，可以再不同的 SQL 间传递值。 用户自定义变量的声明方法形如：@var_name，其中变量名称由字母、数字、“.”、“_”和“$”组成。当然，在以字符串或者标识符引用时也可以包含其他字符（例如：@&#8217;my-var&#8217;，@&#8221;my-var&#8221;，或者@`my-var`）。 用户自定义变量是会话级别的变量。其变量的作用域仅限于声明其的客户端链接。当这个客户端断开时，其所有的会话变量将会被释放。 用户自定义变量是不区分大小写的。 使用 SET 语句来声明用户自定义变量： 在使用 SET 设置变量时，可以使用“=”或者“:=”操作符进行赋值。 当然，除了 SET 语句还有其他赋值的方式。比如下面这个例子，但是赋值操作符只能使用“:=”。因为“=”操作符将会被认为是比较操作符。 mysql&#62; SET @t1=1, @t2=2, @t3:=4; mysql&#62; SELECT @t1, @t2, @t3, @t4 := @t1+@t2+@t3;<div class="read-more"><a class="btn read-more-btn" href="https://blog.ihuxu.com/explaination-of-the-mysql-variables-usage-and-the-use-case/">Read More</a></div>]]></description>
		
					<wfw:commentRss>https://blog.ihuxu.com/explaination-of-the-mysql-variables-usage-and-the-use-case/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
			</item>
		<item>
		<title>基于 libgit2 C 语言库的 php-git 扩展 fix bug 辛酸史</title>
		<link>https://blog.ihuxu.com/the-experience-of-the-fixing-libgit2-git-diff-tree-to-tree-bug/</link>
					<comments>https://blog.ihuxu.com/the-experience-of-the-fixing-libgit2-git-diff-tree-to-tree-bug/#comments</comments>
		
		<dc:creator><![CDATA[HU Xiaoxu]]></dc:creator>
		<pubDate>Sat, 27 Aug 2016 09:41:31 +0000</pubDate>
				<category><![CDATA[Computer Language]]></category>
		<category><![CDATA[Computer Science]]></category>
		<category><![CDATA[Dev Problem]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[C]]></category>
		<category><![CDATA[Original]]></category>
		<category><![CDATA[PHP Extension]]></category>
		<guid isPermaLink="false">http://www.ihuxu.com/blog/?p=1181</guid>

					<description><![CDATA[前言 这是一篇极其没有节（nei）操（rong）的文章。除非你真的无聊，请不要阅读，否则后果自负~ 正文 最近，在忙活微博话题组的日构建工具。工具主要的功能并不算复杂。写着写着，外面雨过天晴，居然还放起爆竹了，什么鬼。 构建工具的主要功能正如介绍中所述的那样，提取产品、测试等基本信息、提取版本库（git）信息、检查（编译）源文件、自动部署项目与发送邮件等。在提取 git 库信息时，相对于之前利用 shell_exec PHP 原生函数提取 svn 信息的方式，打算利用扩展来提取信息。一来更规范、更有效率（微乎其微），二来专业。缺点是相对而言部署环境麻烦，因为需要安装 git 扩展到当前 php 运行环境中来。 但是，万万没想到官方推荐的 php-git 扩展库开发版本已有3年没有维护了。索性用吧，又能怎样。 安装 还算顺利，由于公司开发机没有 cmake，yum 源也不可用，懒得配置，直接 download 一套源码。 上述步骤自行领会，注意上述适用于 64 位 Linux 系统，32 位的 Linux 请见上述提到的 php-git 库说明文档。 使用 我们提取的 git 信息基本也就是从上一次部署版本，到该次部署版本之间的 log 和 diff 信息。所以，第一件事情，就是拿到这段的 commit hash 值。关于下文中提到的 commit hash 和 tree hash 概念可以自行 google 或参见博客libgit2使用教程（特别篇）几个基本概念说明。 在拿到 commit hash 之后，将通过 git_diff_tree_to_tree 方法拿到每个 commit hash 之间的 diff 信息。通过方法名可以知道，这个 diff 信息是通过两个 tree 拿到的。 调用代码：<div class="read-more"><a class="btn read-more-btn" href="https://blog.ihuxu.com/the-experience-of-the-fixing-libgit2-git-diff-tree-to-tree-bug/">Read More</a></div>]]></description>
		
					<wfw:commentRss>https://blog.ihuxu.com/the-experience-of-the-fixing-libgit2-git-diff-tree-to-tree-bug/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
			</item>
		<item>
		<title>关于微博话题组软件构建与发布工程的分享</title>
		<link>https://blog.ihuxu.com/the-share-of-the-release-engineering-at-sina-weibo-topic-team/</link>
					<comments>https://blog.ihuxu.com/the-share-of-the-release-engineering-at-sina-weibo-topic-team/#respond</comments>
		
		<dc:creator><![CDATA[HU Xiaoxu]]></dc:creator>
		<pubDate>Sun, 14 Aug 2016 14:58:56 +0000</pubDate>
				<category><![CDATA[Computer Science]]></category>
		<category><![CDATA[Technical Summary]]></category>
		<category><![CDATA[Original]]></category>
		<guid isPermaLink="false">http://www.ihuxu.com/blog/?p=999</guid>

					<description><![CDATA[针对于“发布工程（Release Engineer）”，也许大家并不陌生。如维基百科中介绍： Release engineering, frequently abbreviated as RE or as the clipped compound Releng, is a sub-discipline in software engineering concerned with the compilation, assembly, and delivery of source code into finished products or other software components. Associated with the software release life cycle, it was said by Boris Debic of Google Inc. 对于一个有着庞大开发团队的成熟公司来说，构建工程显得格外重要。这样一个或者若干个由成百上千个开发成员支持的软件产品来说，构建与发布无非是非常严峻的考验。 然而，目前而言，我们团队在构建发布上仍有着很大的提升空间。 我们的问题 首先介绍下我们组。我们组负责微博的话题业务，每天有着成百上千万的访问量级。核心开发人员一共有 15 人左右。然而，尽管是 15 人的团队，软件的构建与发布流程也显得很重要。 在刚进入团队时，并没有构建概念，同样在发布流程上做的也不够衔接与完善。当有产品提出需求之后，技术 Leader 在进行需求拆分后合理分配给每个开发人员。之后，每个开发人员将以自己的姓名与时间从话题业务版本库的主干上 Check Out 一个分支。待开发完成之后，进入测试申请流程。常规情况下要进行三轮的测试：分支内网测试、分支仿真测试与主干回归测试。在这三轮测试顺利通过之后，我们将通过上线系统（QuikBuild）进入上线流程。 至始至终我们都遵循着上面的流程，然而，会发现如下问题。 面对上面的问题，我们及时地做了调整。首先，在会议讨论后，我们决定先在项目中融入持续集成与持续交付的概念。 发布工程<div class="read-more"><a class="btn read-more-btn" href="https://blog.ihuxu.com/the-share-of-the-release-engineering-at-sina-weibo-topic-team/">Read More</a></div>]]></description>
		
					<wfw:commentRss>https://blog.ihuxu.com/the-share-of-the-release-engineering-at-sina-weibo-topic-team/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>高并发、分布式数据库场景下需要注意的 UPDATE SQL 写法</title>
		<link>https://blog.ihuxu.com/the-problem-of-the-distribution-mysql-to-be-focused-in-the-hight-concurent-request/</link>
					<comments>https://blog.ihuxu.com/the-problem-of-the-distribution-mysql-to-be-focused-in-the-hight-concurent-request/#respond</comments>
		
		<dc:creator><![CDATA[HU Xiaoxu]]></dc:creator>
		<pubDate>Tue, 09 Aug 2016 05:45:26 +0000</pubDate>
				<category><![CDATA[Computer Science]]></category>
		<category><![CDATA[Middleware]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Original]]></category>
		<guid isPermaLink="false">http://www.ihuxu.com/blog/?p=968</guid>

					<description><![CDATA[业务模块 超级话题签到积分 具体场景 更新签到积分行为 表 integration_record &#8211; 每次产生积分行为的记录表。即每当用户产生积分行为（如：在超级话题内进行签到、转发和回复等行为），就会增加一条 integration_record 表的记录。表明该用户在该超级话题下通过哪些行为产生了多少积分增量。 integration &#8211; 每个用户的总积分表。即在每次写入一条 integration_record 记录后，会将积分增量累计加入到该表的总积分字段中。表明目前为止，该用户在该超级话题下通过积分行为一共获取的积分总数。 表的细节就不给出了（也没必要）。这两张表都以话题 ID（topic_id）和用户 ID（uid_id）进行联合索引。 具体问题 在某些情况下，某个用户所在某个话题下的所有 integration_record 记录的积分总和小于该用户在该话题下的 integration 表记录的总积分。 异常日志 通过检查线上异常日志发现，会偶发出现更新 integration 表记录返回0（更新影响记录行数为 0）的情况。但理论上不应该出现这种情况。 分析 进而考虑是由于数据库主从同步的延迟导致。为什么这么猜测？看下面SQL： update integration&#160;set integration = ? where topic_id = ? and uid = ? 上面为改动前（有问题）的 SQL。其中第一个问号代表当前需要更新的积分总数。问题就出现在这个总数上。 这个总数是由当前用户产生的积分行为所增加分数与当前 integration 表中该用户的积分总数（读于从库）之和。 所以，在高并发的请求下，会出现同时待同步如下一些SQL： update integration&#160;set integration = 1720 where topic_id = abc and uid = 12345678 update integration&#160;set integration = 1720 where topic_id<div class="read-more"><a class="btn read-more-btn" href="https://blog.ihuxu.com/the-problem-of-the-distribution-mysql-to-be-focused-in-the-hight-concurent-request/">Read More</a></div>]]></description>
		
					<wfw:commentRss>https://blog.ihuxu.com/the-problem-of-the-distribution-mysql-to-be-focused-in-the-hight-concurent-request/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Powerline 插件安装之 Vim 篇（Mac）</title>
		<link>https://blog.ihuxu.com/the-powerline-plugin-installation-in-vim/</link>
					<comments>https://blog.ihuxu.com/the-powerline-plugin-installation-in-vim/#comments</comments>
		
		<dc:creator><![CDATA[HU Xiaoxu]]></dc:creator>
		<pubDate>Thu, 23 Jun 2016 07:23:57 +0000</pubDate>
				<category><![CDATA[Computer Science]]></category>
		<category><![CDATA[Dev Tool]]></category>
		<category><![CDATA[Vim]]></category>
		<category><![CDATA[IDE]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Original]]></category>
		<category><![CDATA[Powerline]]></category>
		<category><![CDATA[VIM]]></category>
		<guid isPermaLink="false">http://www.ihuxu.com/blog/?p=912</guid>

					<description><![CDATA[Powerline 是 Vim 的状态栏插件，同时也提供状态栏和提示窗口功能给其他一些应用，包括 zsh，bash，Tmux，IPython，Awesome，i3 和 Qtile。这篇文字只谈 Vim 上的安装。 环境与工具 系统：OS X EI Capitan version 10.11.5 终端：Terminal Vim ：v7.4.1914 Xcode: 7.3.1（Xcode 的版本过低会影响一些依赖库的安装，我在 6.5 的情况下安装一些软件会出些问题，避免麻烦升级下） Python：3.5.1 源码： python: https://www.python.org/ftp/python/3.5.1/Python-3.5.1.tar.xz vim: https://github.com/vim/vim/archive/v7.4.1949.tar.gz 安装 Python ./configure&#160; --prefix=/usr/local/python351 make &#38; make install Vim Vim 的安装需要使用 Python 的配置 ./configure --prefix=/usr/local/vim741949 --enable-multibyte --with-tlib=ncurses --enable-cscope --with-features=big --with-python3-config-dir=/usr/local/python351/lib/python3.5/config-3.5m --enable-pythoninterp make &#38; make install 字体 将源码（https://github.com/powerline/fonts）clone 到本地后，执行如下命令： ./install.sh 配置 .vimrc 我是用 Vundle 来管理 Vim 插件的，所以需要配置如下项: Plugin 'powerline/powerline'&#160; 在 Vim<div class="read-more"><a class="btn read-more-btn" href="https://blog.ihuxu.com/the-powerline-plugin-installation-in-vim/">Read More</a></div>]]></description>
		
					<wfw:commentRss>https://blog.ihuxu.com/the-powerline-plugin-installation-in-vim/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
			</item>
		<item>
		<title>Vim 使用技巧之只有用了才会懂“最好的 IDE 是 Vim”</title>
		<link>https://blog.ihuxu.com/once-you-have-used-vim-you-would-think-other-ides-are-so-bad/</link>
					<comments>https://blog.ihuxu.com/once-you-have-used-vim-you-would-think-other-ides-are-so-bad/#respond</comments>
		
		<dc:creator><![CDATA[HU Xiaoxu]]></dc:creator>
		<pubDate>Mon, 06 Jun 2016 11:16:19 +0000</pubDate>
				<category><![CDATA[Computer Science]]></category>
		<category><![CDATA[Dev Tool]]></category>
		<category><![CDATA[Vim]]></category>
		<category><![CDATA[IDE]]></category>
		<category><![CDATA[Original]]></category>
		<category><![CDATA[TMUX]]></category>
		<category><![CDATA[VIM]]></category>
		<guid isPermaLink="false">http://www.ihuxu.com/blog/?p=865</guid>

					<description><![CDATA[半年前，我还在诸如 Eclipse、ZendStudio 等 IDE 里徘徊。然而，这半年对于 Vim 的使用，不得不说，Vim 的效率是更高的。代价是需要时间来自定义并熟悉自己的 Vim。 这里，只写下迄今为止对于 Vim + Tmux 的使用感受，以及展示 Vim 的使用技巧（至于如何入门 Vim 请自行 Google）。 为什么要用 Vim？ 随时随地，摆脱环境的束缚，你只需要一个终端（Terminal）。 你不必在键盘和鼠标之前来回切换（我压根就觉得鼠标是不服务于“编码工作”的产品），所有的操作都在指尖下的按键。 高程度的自定义，所以不要来拷贝他人的配置文件，很伤。 其他 IDE 中的功能在 Vim 里基本能找到替代品，幸福指数飙升~ 耳听十遍，不如亲眼一见 winmanager, ftaglist, neardtree, bufexplorer和tmux等的应用 ctrlp的应用 Vim 使用技巧 看到好多人，为了学习技术买了 n 多本书。可是有没有考虑过，书本带来的学习效果真的会高于互联网学习方式么？为什么要买那么多书呢？ 个人而言，对于互联网技术，更适合我的方式是 Google + 社区 + Github + 等等。所以，在 Youtube 上的两个关于 Vim + Tmux 的视频我推荐给大家，我已经传到土豆上了。 Vim + Tmux: http://www.tudou.com/programs/view/WqYvxcISogQ tmux:&#160;http://www.tudou.com/listplay/eLwVUsV5A-M/3irTcoFS19k.html 建议 用Vundle来管理你的插件 不要拷贝其他人的配置文件 看完这篇文章的疑问利用google来解决（如果你愿意等待，可以在下方留言）]]></description>
		
					<wfw:commentRss>https://blog.ihuxu.com/once-you-have-used-vim-you-would-think-other-ides-are-so-bad/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>关于“如何开发 PHP 扩展”的学习小结</title>
		<link>https://blog.ihuxu.com/the-summary-of-the-php-extension-learing/</link>
					<comments>https://blog.ihuxu.com/the-summary-of-the-php-extension-learing/#respond</comments>
		
		<dc:creator><![CDATA[HU Xiaoxu]]></dc:creator>
		<pubDate>Tue, 08 Mar 2016 09:28:37 +0000</pubDate>
				<category><![CDATA[Computer Language]]></category>
		<category><![CDATA[Computer Science]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Original]]></category>
		<category><![CDATA[PHP Extension]]></category>
		<guid isPermaLink="false">http://www.ihuxu.com/blog/?p=763</guid>

					<description><![CDATA[近期，工作上的业务并不是很忙。做了大半年的业务逻辑，尽管在 PHP 编码习惯和技巧上有所进步，初步熟悉了在高并发下 Redis 和 Memcache 缓存的使用和注意事项。但，应该借此闲暇时间探索下 PHP 底层的一些原理。这样，才是会有质的提升，写出更好的代码。 正如那句话“PHP 取得成功的一个主要原因之一是她拥有大量的可用扩展”，那就从 PHP 扩展入手了解下。 在此之前，大家肯定都了解“PHP 是 C 写的”。于是打开了 PHP 的源码，列出跟目录列表如下图： PHP（5.6.4）跟目录列表 看到了熟悉的以后缀 .c 结尾的源文件。如图，有个名为“Zend”的文件夹很重要，这个就是 PHP 的核心。于是在网上搜到了两个若干 PHP 扩展的教程： http://www.laruence.com/2009/04/28/719.html http://www.walu.cc/phpbook 起初，耐心的看了 http://www.walu.cc/phpbook 的教程。并没有读完，只是看了前面的前 8 章。之后按着 http://www.laruence.com/2009/04/28/719.html 的教程，仿照着写了一个扩展。进行了编译、排查错误、编译、安装和测试等步骤，有了整体的感知。 在开发的过程中，可贵的也是难点就是要遵循 PHP 的扩展开发标准来做。我想，只要是熟悉了这个标准，至少写出一些简单的扩展是 OK 的了。在此基础上，继续深入的了解其特性，才可以开发出稳定、安全且高性能的扩展吧。 上述提到的源码（供学习交流之用）：http://github.com/genialx/geno_file]]></description>
		
					<wfw:commentRss>https://blog.ihuxu.com/the-summary-of-the-php-extension-learing/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>关于 rsync 工具的安装、配置与进行文件同步与备份的使用流程</title>
		<link>https://blog.ihuxu.com/synchronization-and-backup-process-installation-and-configuration-files-on-rsync-tools/</link>
					<comments>https://blog.ihuxu.com/synchronization-and-backup-process-installation-and-configuration-files-on-rsync-tools/#respond</comments>
		
		<dc:creator><![CDATA[HU Xiaoxu]]></dc:creator>
		<pubDate>Wed, 02 Mar 2016 10:04:13 +0000</pubDate>
				<category><![CDATA[Computer Science]]></category>
		<category><![CDATA[Dev Tool]]></category>
		<category><![CDATA[Others]]></category>
		<category><![CDATA[Original]]></category>
		<category><![CDATA[RSYNC]]></category>
		<guid isPermaLink="false">http://www.ihuxu.com/blog/?p=746</guid>

					<description><![CDATA[安装 linux yum install rsync 配置 编辑文件: vim /etc/xinetd.d/rsync 内容如下： # default: off # description: The rsync server is a good addition to an ftp server, as it \ # allows crc checksumming etc. service rsync { disable = no flags = IPv6 socket_type = stream wait = no user = root server = /usr/bin/rsync server_args = --daemon log_on_failure += USERID } 创建配置文件 touch /etc/rsyncd.conf 内容如下 # rsync 服务执行的所属用户 ID<div class="read-more"><a class="btn read-more-btn" href="https://blog.ihuxu.com/synchronization-and-backup-process-installation-and-configuration-files-on-rsync-tools/">Read More</a></div>]]></description>
		
					<wfw:commentRss>https://blog.ihuxu.com/synchronization-and-backup-process-installation-and-configuration-files-on-rsync-tools/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>[开发中] Java 实现仿 QQ 界面多人聊天客户端程序</title>
		<link>https://blog.ihuxu.com/java-chat-client-setup-like-qq-interface/</link>
					<comments>https://blog.ihuxu.com/java-chat-client-setup-like-qq-interface/#comments</comments>
		
		<dc:creator><![CDATA[HU Xiaoxu]]></dc:creator>
		<pubDate>Fri, 12 Feb 2016 04:40:09 +0000</pubDate>
				<category><![CDATA[Computer Science]]></category>
		<category><![CDATA[My Project]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Original]]></category>
		<category><![CDATA[QQ]]></category>
		<guid isPermaLink="false">http://www.ihuxu.com/blog/?p=651</guid>

					<description><![CDATA[记得几年前，在校期间写过一个聊天程序，也发布了一篇博客在 csdn 上。然而，近期有好多网友加我 QQ 索要源码，可惜的是源码早已消失在网络中了。所以，借此闲暇时间重写一次 Java 多人聊天客户端程序，以供爱好者学习交流之用。如下是每日程序的进展日志。 项目源码： 客户端 -&#62;&#160;github.com/genialx/ChatX 服务端 -&#62;&#160;github.com/genialx/ChatXServer 前面的话 对于 Java，笔者算是新手，没有用 Java 做过实际的项目。所以，在做这个项目的过程中，进行了大量的调研工作，有很多问题都无法短时间内解决。固然，项目中的代码是很糟糕的。不过，有时间会进行深入的学习来优化项目甚至重构代码。 进展日志 2016.02.12 项目不是起于今日，目前已经完成了客户端的登陆界面，正在着手完善朋友列表的界面。 登陆界面 朋友列表 遇到的一些不是问题的问题&#8230; 容器组件半透明的问题 起初进行了搜索引擎，大致分为两种。一种是利用重写父类的重画方法，个人尝试了网上的代码几次，不成功，也觉得 Java 应该能提供半透明的 API，不至于还要重写，于是就放弃了。 第二种是利用 com.sun.awt.AWTUtilities 类进行设置。 但是，了解到 AWT 在 Jre8 中不再存在，同时网上描述说兼容不好，所以放弃了。 于是，在网上找到了这个很简单的 API，也刚好能够满足我的预期效果，如图“朋友列表”中的透明效果。 如果是 JScrollPane 容器的话，需要如下设置。 这是因为 JScrollPane 容器管理着视口、可选的垂直和水平滚动条以及可选的行和列标题视口。 JScrollPane 组成 JTextField 容器输入文字内边距设置问题（未解决） 首先，我在 Eclipse 的自动方法提示窗口里面找了所有 set 开头的方法，并在搜索引擎搜了几圈，最终也没能找到解决方案。感觉搜索引擎中基本上没有这个问题的提问，估计是我的关键词有问题吧。最后，通过改变 JTextField 的位置，以及 JTextField 所在容器的背景颜色来实现，输入框的内左边距的效果。 JScrollPane 滚动时画布重画的问题（未解决） 如“朋友列表”界面，由于 JScrollPane 采用了半透明的机制，导致窗口滚动时半透明的效果失效，显示灰白色的底色。如下图： JScrollPane 滚动时半透明失效 而当触发重画方法时，JScrollPane 界面又恢复半透明效果。所以，通过给 JScrollPane 加监听鼠标滚轮事件。 但是仍然无效，原因应该是 JScrollPane<div class="read-more"><a class="btn read-more-btn" href="https://blog.ihuxu.com/java-chat-client-setup-like-qq-interface/">Read More</a></div>]]></description>
		
					<wfw:commentRss>https://blog.ihuxu.com/java-chat-client-setup-like-qq-interface/feed/</wfw:commentRss>
			<slash:comments>5</slash:comments>
		
		
			</item>
		<item>
		<title>GO 语言实现的多人 WEB 聊天室</title>
		<link>https://blog.ihuxu.com/chat-room-in-go/</link>
					<comments>https://blog.ihuxu.com/chat-room-in-go/#respond</comments>
		
		<dc:creator><![CDATA[HU Xiaoxu]]></dc:creator>
		<pubDate>Sat, 02 Jan 2016 11:28:02 +0000</pubDate>
				<category><![CDATA[Computer Science]]></category>
		<category><![CDATA[My Project]]></category>
		<category><![CDATA[GO]]></category>
		<category><![CDATA[Original]]></category>
		<guid isPermaLink="false">http://www.ihuxu.com/blog/?p=612</guid>

					<description><![CDATA[前段时间的工作，大部分都在“热门微博推荐流”的性能优化上。前期通过源码分析对源码的逻辑进行了优化，其中可优化的地方大多都是落在了 Redis 的多次调用、外部接口的调用以及自身过多的 IO 操作。近期，提出利用 GO 语言做一层 RPC 服务，将较数据层进行封装。 所以，为了尽快熟悉并上手 GO，先写个小程序熟悉熟悉~ 程序名称：聊天室 源码地址：http://github.com/genialx/guring 截图： 程序中固然存在不合理的地方，仅供参考~]]></description>
		
					<wfw:commentRss>https://blog.ihuxu.com/chat-room-in-go/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>PHP 数组函数 array_diff()、array_merge() 与数组操作符 +</title>
		<link>https://blog.ihuxu.com/php-array-diff-array-merge/</link>
					<comments>https://blog.ihuxu.com/php-array-diff-array-merge/#respond</comments>
		
		<dc:creator><![CDATA[HU Xiaoxu]]></dc:creator>
		<pubDate>Thu, 10 Dec 2015 08:56:21 +0000</pubDate>
				<category><![CDATA[Computer Language]]></category>
		<category><![CDATA[Computer Science]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Original]]></category>
		<guid isPermaLink="false">http://www.ihuxu.com/blog/?p=564</guid>

					<description><![CDATA[array_diff() 函数是以值为判断依据，比如： 输出： 同样，array_merge 函数也是以值为判断依据进行合并数组，如下： 输出: 问题来了，如果利用数组操作符 +，进行两个数组的合并，却是以键为判断依据： 输出：]]></description>
		
					<wfw:commentRss>https://blog.ihuxu.com/php-array-diff-array-merge/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>利用 xhprof（PHP）扩展进行 WEB 性能分析</title>
		<link>https://blog.ihuxu.com/web-performance-analysis-using-php-xhprof/</link>
					<comments>https://blog.ihuxu.com/web-performance-analysis-using-php-xhprof/#respond</comments>
		
		<dc:creator><![CDATA[HU Xiaoxu]]></dc:creator>
		<pubDate>Sat, 05 Dec 2015 13:37:41 +0000</pubDate>
				<category><![CDATA[Computer Language]]></category>
		<category><![CDATA[Computer Science]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Original]]></category>
		<category><![CDATA[XHPROF]]></category>
		<guid isPermaLink="false">http://www.ihuxu.com/blog/?p=512</guid>

					<description><![CDATA[最近工作有些小忙，经常加班，偶尔还会通宵。但最终热门微博“混合流”顺利地全量上线了。可是，从性能角度来说，还是有不少的提升空间的。 下面说下利用 xhprof 来进行 WEB 性能的分析。 安装 xhprof 扩展 官方的文档胜过一切 =&#62; http://php.net/xhprof 注意：如果想利用 xhprof 绘图，那么需要将系统默认禁用函数打开。 部署xhprof的运行环境 经过上面的配置，在你跑过项目后，xhprof 会输出一份报告文件。不过，这份文件的内容是被序列化的数组。所以，需要搭建一个能够读取该数据文件的 WEB 环境。 这里给一份 xhprof 环境的代码：http://pan.baidu.com/s/1bnLvmrl 之后通过访问 xhprof 的环境，你会看到如下报告界面。 xhprof 文件列表（/xhprof_html/list.php） 图标形式的 xhprof 报告(/xhprof_html/index.php） Function Name 方法名称 Calls 被调用次数 Incl. Wall Time 该函数执行时间（包含内部其他函数调用的时间） Excl. Wall Time 该函数执行时间（不包含内部其他函数调用的时间） 流程图形式的xhprof报告（/xhprof_html/callgraph.php） 需要关注的几点： 同一方法被过多次的调用（也许是无谓的循环导致的） 耗时是否落到了外部接口上（会影响TPS &#8211; 每秒请求数量） 是否有内存的过多消耗（会影响计算效率）]]></description>
		
					<wfw:commentRss>https://blog.ihuxu.com/web-performance-analysis-using-php-xhprof/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>高并发场景下的缓存使用误区</title>
		<link>https://blog.ihuxu.com/the-cache-usage-errors-in-high-concurrency-scenarios/</link>
					<comments>https://blog.ihuxu.com/the-cache-usage-errors-in-high-concurrency-scenarios/#respond</comments>
		
		<dc:creator><![CDATA[HU Xiaoxu]]></dc:creator>
		<pubDate>Thu, 08 Oct 2015 05:03:33 +0000</pubDate>
				<category><![CDATA[Computer Language]]></category>
		<category><![CDATA[Computer Science]]></category>
		<category><![CDATA[Memcached]]></category>
		<category><![CDATA[Middleware]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Redis]]></category>
		<category><![CDATA[Original]]></category>
		<guid isPermaLink="false">http://www.ihuxu.com/blog/?p=402</guid>

					<description><![CDATA[十一聚会，某谈及人生理想。我要的是“地位，身份和爱情！”，其实就是金钱，面子和美女。O.O 正文 9月份，连续两天（AB 两天）线上出现业务故障，redis 监控曲线瞬间上涨。 业务场景：一千万 UV / 日 redis监控曲线 （修改图片好麻烦，曲线意会下吧~）： redis日志 业务代码 &#160; 问题 由业务代码和redis日志可以看出，正常情况下通常会有一次删和一次写之后，会出现大量的读。然而，日志中则出现了大量的写入。这就是高并发时导致同时写入后，也许因为写入量特大，导致下次读取失败后继续进行写入，最后把 redis 拖垮。 解决 如果不需要进行排序截取等操作可以换用 Memcached 缓存 在高并发情况下应对 redis 加事务机制 redis事务 修改后的业务代码 注：封面配图为朋友圈图片]]></description>
		
					<wfw:commentRss>https://blog.ihuxu.com/the-cache-usage-errors-in-high-concurrency-scenarios/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Git 与 SVN 的使用感受</title>
		<link>https://blog.ihuxu.com/the-feeling-of-using-the-git-and-the-svn/</link>
					<comments>https://blog.ihuxu.com/the-feeling-of-using-the-git-and-the-svn/#respond</comments>
		
		<dc:creator><![CDATA[HU Xiaoxu]]></dc:creator>
		<pubDate>Tue, 19 May 2015 05:40:52 +0000</pubDate>
				<category><![CDATA[Computer Science]]></category>
		<category><![CDATA[Dev Tool]]></category>
		<category><![CDATA[Git]]></category>
		<category><![CDATA[Original]]></category>
		<category><![CDATA[SVN]]></category>
		<guid isPermaLink="false">http://www.ihuxu.com/blog/?p=203</guid>

					<description><![CDATA[工作环境需要，分别接触了 Git 和 SVN 版本控制工具。接触不久，尽管这两种工具都不是很熟悉，目前仅能达到满足简单的工作需求（有时还需要查引擎）。但，还是有一些感受以记录。 分支（branches）与里程碑（tags） Git 的分支和里程碑很有趣和简单，可以快速地在当前工作区切换不同的分支和里程碑。 SVN 的分支和里程碑本身就是一个目录（拷贝），目录下分别有一个 .svn 的文件夹以存储版本信息。 所以，SVN 切换分支很麻烦，需要切换工作区(每一个工作区只对应服务器的某一分支）。而 Git 却很方便。 集中式与分布式 这个事情和上面的分支和里程碑是有重叠的地方的。 Git 采取的是分布式。简单的说就是每台 checkout 过代码的笔记本上都有着一个完整的代码库。 而 SVN 却是集中式的，只有一个是代码仓库，就是服务器。 所以，Git可以本地提交，SVN需联网提交。 Git 是没有中心服务器的，每个人机器上都是一个完整的库，我们平时开发代码时的中央服务器其实和我们自己机器上的库内容是完全一样的（格式有点不同，是 bare 的）。虽然平时大家都是将代码提交到中央服务器上再统一pull别人的代码，但实际情况你可以总是 pull 张三的库，然后 push 给李四等等操作。个人认为去中心化是 Git（也包括其他分布式 VCS）最伟大的改变。去中心化意味着没有权威、没有主力，所有人都是平等的。这概念本身看起来好像没什么，但实际对社区影响是巨大的，去看看 http://github.com 上的fork功能，你可以fork任何一个你喜欢的项目，接着按自己的喜好修改成自己的项目，或是发起 pull request 请原作者 merge 你的功能到他们项目里去（这同样也得益于 Git 另一项与 SVN 很大不同的功能——分支策略），而且大多数开源项目都会鼓励你去 fork 它们。这里面没有权威，没有主从，所有人只要有兴趣都可以在其他人的基础上去构建更强大或是更有领域针对性的项目。大家不是为了开发某个项目而来，而是为了贡献更强的功能给社区，这样最终的项目将是整个社区所有人共同努力的结果，将生生世世繁衍不息。当然，去中心化也可能会引发一些问题，比如 Linux 的各种发行版本有时候让人难以抉择，但相信市场之手会帮我们出选择。 本地版本控制系统 分布式的版本控制系统 集中式的版本控制系统 参考 如何理解 Git 的分布式？ Git与svn的区别 蒋鑫：为什么 Git 比 SVN 好 GIT和SVN之间的五个基本区别 Git详解之一：Git起步]]></description>
		
					<wfw:commentRss>https://blog.ihuxu.com/the-feeling-of-using-the-git-and-the-svn/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>WEB 开发之前端与后端通信解决方案</title>
		<link>https://blog.ihuxu.com/web-front-back-communicating/</link>
					<comments>https://blog.ihuxu.com/web-front-back-communicating/#comments</comments>
		
		<dc:creator><![CDATA[HU Xiaoxu]]></dc:creator>
		<pubDate>Tue, 14 Apr 2015 15:16:10 +0000</pubDate>
				<category><![CDATA[Computer Science]]></category>
		<category><![CDATA[System Design]]></category>
		<category><![CDATA[Ajax]]></category>
		<category><![CDATA[API]]></category>
		<category><![CDATA[Original]]></category>
		<guid isPermaLink="false">http://www.ihuxu.com/blog/?p=63</guid>

					<description><![CDATA[每天都得找点乐子，今天的乐子就是“WEB开发中前端与后端通信的解决方案”。 首先，说一下“神圣”的需求。假设，我们面前是一个报名活动的页面。所有的逻辑都发生在这报名按钮上，下面是导图： 做法一 按钮是一个链接，当我们用可爱的手指轻轻触碰它时。它会告诉浏览器，我是一个链接。之后，浏览器被跳转到一个新的地址上。与此同时，后端会执行当前的逻辑，渲染对应的 WEB 页面。 这种做法很糟糕： 1、用户体验不好，跳转页面的吞吐量比较高，加大用户的等待时间 2、同时，也加大服务器的负担 3、代码冗余度较高，需要写若干个前端页面和后端方法 做法二 那么，用 Ajax 来实现前后端的通信（异步）也许是个不错的做法。既然，谈到通信，那么必定要有个标准。那，标准是个什么东西？ 举个例子（秒懂！哈哈） 公认的标准脸型 不符合标准的脸型 所以，你知道。如果程序没有标准，是一件多么令人“恼怒”的事情。 需要两个 PHP 类库： 标准接口： 实现类库： 后端： 前端 HTML： 前端Javascript: 完善 当然，这个模式可以根据不同项目做少许改变。 目前，也许会遇到这样的问题。当逻辑比较复杂时，那么注册在这个”加入“按钮上的事件函数的处理逻辑，会通过多次请求服务器来判断当前的状态（是或否）。这种情况，对于编码和用户体验（延时等待）都不是好的。所以，其实也可以在报名页面渲染时，把必要的字段放在 input[type=&#8217;hidden&#8217;] 中。这样，也就解决了前端页面通过 Ajax 多次请求服务器的问题。 注：该文章代码均为伪代码，不可直接复用。文中 PHP 类库样例代码基于 ThinkPHP 框架。]]></description>
		
					<wfw:commentRss>https://blog.ihuxu.com/web-front-back-communicating/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
			</item>
		<item>
		<title>微信支付 JSAPI 开发中的问题</title>
		<link>https://blog.ihuxu.com/wechat-pay-sdk-development/</link>
					<comments>https://blog.ihuxu.com/wechat-pay-sdk-development/#respond</comments>
		
		<dc:creator><![CDATA[HU Xiaoxu]]></dc:creator>
		<pubDate>Sun, 23 Nov 2014 15:15:13 +0000</pubDate>
				<category><![CDATA[Computer Science]]></category>
		<category><![CDATA[Dev Problem]]></category>
		<category><![CDATA[Original]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[SDK]]></category>
		<category><![CDATA[WeChat]]></category>
		<guid isPermaLink="false">http://www.ihuxu.com/blog/?p=89</guid>

					<description><![CDATA[前言：这篇文章讲的是利用微信官方提供的 JSAPI 接口，实现微信网页支付。希望在看之前，要确认以下几件事情，否则会在解决问题时很费解。 ①　接口文档版本号是 V3.3（在官方提供的 PHP DEMO 中的 README.txt 文件中查看。当然，也可以参考压缩包的名字（wxm-payment-biz-api218f8e.zip）来确认版本 ②　微信支付 PDF 文档的版本为 V3.3.7（如果上述版本对了，这步应该也是一致的，因为这两个文件是在一个包里） ③　该文章说的是 JSAPI 的开发 简单看了下微信支付的文档和源码（压缩包名：wxm-payment-biz-api218f8e.zip；PDF 文档名：【微信支付】微信公众号支付接口文档V3.3.7.pdf；）。然后，修改了微信的配置文件。有如下几个配置项值得注意： 1、 MCHID 注释是“受理商 ID，身份标识”。可以在邮件中查看，这个邮件是在申请支付的某个流程中回执的。由于我不是微信号的“主人”，所以具体在哪个环节不好确定。同时，邮件中还会有个密码。利用这个 MCHID 和密码可以到微信商户平台（https://pay.weixin.qq.com/）登录，进入管理商户订单的界面。 2、 KEY&#160; 这个 KEY 有些苦逼啊，文档注释说是“商户支付密钥 Key。审核通过后，在微信发送的邮件中查看”。但并没有在邮件里找到这个 KEY ！算了，百度了下，发现是在微信商户平台设置的。利用上面提到的账户信息登录商户平台后，点击左侧的“安全设置”（记不清了，如果不是这个关键字，找到证书管理的选项即可），然后需要安装浏览器证书插件后，手动设置这个 KEY。随意设置，可以用 MD5 加密后的字符串，比如 MD5(&#8220;Foo&#8221;)。 3、 SSLCERT_PATH 注释为“证书路径，注意应该填写绝对路径”，给的默认格式为“/xxx/xxx/xxx/WxPayPubHelper/cacert/apiclient_cert.pem”。但是，我直接用的“http://www.domain.com/wxpay/cacert/apiclient_cert.pem”这种格式。因为，简单看了下利用这个常量的调用代码，用的是 Curl 函数，那么我想用 http 开头的链接应该不会有问题了。 4、 SSLKEY_PATH 同上 5、 CURL_TIMEOUT&#160; 这个常量在这个版本的 DEMO 中没有用到，直接写的 30，开发者注意修改。 刚才介绍了几个有歧义的常量，下面还有个问题需要注意。在 WxPayPubHelper.php 文件中的第155行的常量有拼写错误。 官方的文档我很无语哦！&#160;：《 好了，配置项 OK 了。程序部署到网站的 wxpay 项目下(http://www.domain.com/wxpay/)。然后在微信公众号管理后台的微信支付的界面中进行了支付授权目录的设置。设置后不知道为什么显示为空，我没有注意。同时，我在支付测试目录中也设置了路径，同时把测试号的微信 ID 填入白名单。 这时，测试的时候一直提示 system:access_denied（同：system:not_allowed）。 接着，仔细看了下 PDF 文档，觉得问题出现在支付授权目录下，果不其然。切记，阅读官方文档是多么的重要！ 解决步骤：把测试账号的微信 ID<div class="read-more"><a class="btn read-more-btn" href="https://blog.ihuxu.com/wechat-pay-sdk-development/">Read More</a></div>]]></description>
		
					<wfw:commentRss>https://blog.ihuxu.com/wechat-pay-sdk-development/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
