<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>并发 on 古思乱想</title><link>https://blog.gusibi.site/tags/%E5%B9%B6%E5%8F%91/</link><description>Recent content in 并发 on 古思乱想</description><generator>Hugo</generator><language>zh-cn</language><lastBuildDate>Tue, 01 Oct 2024 12:46:43 +0800</lastBuildDate><atom:link href="https://blog.gusibi.site/tags/%E5%B9%B6%E5%8F%91/index.xml" rel="self" type="application/rss+xml"/><item><title>深入探讨字符串和 JSON 对比技术：多语言实现指南</title><link>https://blog.gusibi.site/post/string-json-comparison-multilang/</link><pubDate>Tue, 01 Oct 2024 12:46:43 +0800</pubDate><guid>https://blog.gusibi.site/post/string-json-comparison-multilang/</guid><description>在讨论具体技术之前，我们先来看看为什么这个话题如此重要。在软件开发中，我们经常需要比较两个版本的文本或数据结构。</description></item><item><title>并发模型：线程与锁</title><link>https://blog.gusibi.site/post/thread-and-lock/</link><pubDate>Sun, 19 May 2019 20:29:39 +0800</pubDate><guid>https://blog.gusibi.site/post/thread-and-lock/</guid><description>并发模型：线程与锁</description></item><item><title>《理解 unix 进程》笔记-1</title><link>https://blog.gusibi.site/post/understand-unix-process-note-1/</link><pubDate>Sun, 25 Mar 2018 23:25:53 +0800</pubDate><guid>https://blog.gusibi.site/post/understand-unix-process-note-1/</guid><description>description</description></item><item><title>操作系统线程描述</title><link>https://blog.gusibi.site/post/system-process-3/</link><pubDate>Sat, 24 Mar 2018 12:25:53 +0800</pubDate><guid>https://blog.gusibi.site/post/system-process-3/</guid><description>description</description></item><item><title>操作系统进程描述</title><link>https://blog.gusibi.site/post/system-process-2/</link><pubDate>Tue, 20 Mar 2018 23:25:53 +0800</pubDate><guid>https://blog.gusibi.site/post/system-process-2/</guid><description>description</description></item><item><title>操作系统发展和进程简介</title><link>https://blog.gusibi.site/post/system-process-1/</link><pubDate>Wed, 07 Mar 2018 23:25:53 +0800</pubDate><guid>https://blog.gusibi.site/post/system-process-1/</guid><description>description</description></item><item><title>python并发4：使用thread处理并发</title><link>https://blog.gusibi.site/post/python-thread-note/</link><pubDate>Sun, 02 Jul 2017 16:29:39 +0800</pubDate><guid>https://blog.gusibi.site/post/python-thread-note/</guid><description>python asyncio 介绍</description></item><item><title>python并发3：使用asyncio编写服务器</title><link>https://blog.gusibi.site/post/python-asyncio-server/</link><pubDate>Fri, 30 Jun 2017 16:29:39 +0800</pubDate><guid>https://blog.gusibi.site/post/python-asyncio-server/</guid><description>python asyncio 介绍</description></item><item><title>python并发2：使用asyncio处理并发</title><link>https://blog.gusibi.site/post/python-asyncio/</link><pubDate>Fri, 23 Jun 2017 16:29:39 +0800</pubDate><guid>https://blog.gusibi.site/post/python-asyncio/</guid><description>python asyncio 介绍</description></item><item><title>python并发 1：使用 futures 处理并发</title><link>https://blog.gusibi.site/post/python-concurrency-with-futures/</link><pubDate>Sat, 17 Jun 2017 22:01:51 +0800</pubDate><guid>https://blog.gusibi.site/post/python-concurrency-with-futures/</guid><description>&lt;blockquote&gt;
&lt;p&gt;作为Python程序员，平时很少使用并发编程，偶尔使用也只需要派生出一批独立的线程，然后放到队列中，批量执行。所以，不夸张的说，虽然我知道线程、进程、并行、并发的概念，但每次使用的时候可能还需要再打开文档回顾一下。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;现在这一篇还是 &lt;em&gt;《流畅的python》读书笔记&lt;/em&gt;，译者在这里把future 翻译为“期物”，我觉得不太合适，既然future不能找到一个合适的词汇，暂时还是直接使用 future 吧。&lt;/p&gt;
&lt;h2 id="concurrentfutures"&gt;concurrent.futures&lt;/h2&gt;
&lt;p&gt;future 是一种对象，表示异步执行的操作。这个概念是 concurrent.futures模块和asyncio包的基础。&lt;/p&gt;
&lt;p&gt;concurrent.futures 模块是Python3.2 引入的，对于Python2x 版本，Python2.5 以上的版本可以安装 futures 包来使用这个模块。&lt;/p&gt;
&lt;p&gt;HUGOMORE42&lt;/p&gt;
&lt;p&gt;从Python3.4起，标准库中有两个为Future的类：concurrent.futures.Future 和 asyncio.Future。这两个类作用相同：两个Future类的实例都表示可能已经完成或未完成的延迟计算。&lt;/p&gt;
&lt;p&gt;Future 封装待完成的操作，可放入队列，完成的状态可以查询，得到结果（或抛出异常）后可以获取结果（或异常）。&lt;/p&gt;
&lt;p&gt;我们知道，如果程序中包含I/O操作，程序会有很高的延迟，CPU会处于等待状态，这时如果我们不使用并发会浪费很多时间。&lt;/p&gt;
&lt;h3 id="示例"&gt;示例&lt;/h3&gt;
&lt;p&gt;我们先举个例子：&lt;/p&gt;
&lt;p&gt;下边是有两段代码，主要功能都是从网上下载人口前20的国际的国旗：
第一段代码(flagss.py)是依序下载：下载完一个图片后保存到硬盘，然后请求下一张图片；
第二段代码(flagss_threadpool.py)使用 concurrent.futures 模块，批量下载10张图片。&lt;/p&gt;
&lt;p&gt;运行分别运行两段代码3次，结果如下：&lt;/p&gt;
&lt;p&gt;images.py 的结果如下&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ python flags.py
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;BD BR CD CN DE EG ET FR ID IN IR JP MX NG PH PK RU TR US VN
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;20&lt;/span&gt; flags downloaded in 6.18s
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ python flags.py
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;BD BR CD CN DE EG ET FR ID IN IR JP MX NG PH PK RU TR US VN
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;20&lt;/span&gt; flags downloaded in 5.67s
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ python flags.py
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;BD BR CD CN DE EG ET FR ID IN IR JP MX NG PH PK RU TR US VN
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;20&lt;/span&gt; flags downloaded in 6.55s
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;blockquote&gt;
&lt;p&gt;可以看到，依次下载10张图片，平均需要6秒&lt;/p&gt;</description></item><item><title>python协程3：用仿真实验学习协程</title><link>https://blog.gusibi.site/post/python-coroutine-discrete-event-simulation/</link><pubDate>Thu, 15 Jun 2017 19:22:49 +0800</pubDate><guid>https://blog.gusibi.site/post/python-coroutine-discrete-event-simulation/</guid><description>&lt;p&gt;前两篇我们已经介绍了&lt;a href="https://gusibi.github.io/post/python-coroutine-1-yield/"&gt;python 协程的使用&lt;/a&gt;和&lt;a href="https://gusibi.github.io/post/python-coroutine-yield-from/"&gt;yield from 的原理&lt;/a&gt;，这一篇，我们用一个例子来揭示如何使用协程在单线程中管理并发活动。&lt;/p&gt;
&lt;h2 id="什么是离散事件仿真"&gt;什么是离散事件仿真&lt;/h2&gt;
&lt;p&gt;Wiki上的定义是：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;离散事件仿真将系统随时间的变化抽象成一系列的离散时间点上的事件，通过按照事件时间顺序处理事件来演进，是一种事件驱动的仿真世界观。离散事件仿真将系统的变化看做一个事件，因此系统任何的变化都只能是通过处理相应的事件来实现，在两个相邻的事件之间，系统状态维持前一个事件发生后的状态不变。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;人话说就是一种把系统建模成一系列事件的仿真系统。在离散事件仿真中，仿真“钟”向前推进的量不是固定的，而是直接推进到下一个事件模型的模拟时间。&lt;/p&gt;
&lt;p&gt;假设我们抽象模拟出租车的运营过程，其中一个事件是乘客上车，下一个事件则是乘客下车。不管乘客做了5分钟还是50分钟，一旦下车，仿真钟就会更新，指向此次运营的结束时间。&lt;/p&gt;
&lt;p&gt;事件？是不是想到了协程！&lt;/p&gt;
&lt;p&gt;协程恰好为实现离散事件仿真提供了合理的抽象。&lt;/p&gt;
&lt;p&gt;HUGOMORE42&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;第一门面向对象的语音 Simula 引入协程这个概念就是为了支持仿真。
Simpy 是一个实现离散事件仿真的Python包，通过一个协程表示离散事件仿真系统的各个进程。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="出租车对运营仿真"&gt;出租车对运营仿真&lt;/h2&gt;
&lt;p&gt;仿真程序会创建几辆出租车，每辆出租车会拉几个乘客，然后回家。出租车会首先驶离车库，四处徘徊，寻找乘客；拉到乘客后，行程开始；乘客下车后，继续四处徘徊。&lt;/p&gt;
&lt;p&gt;徘徊和行程所用的时间使用指数分布生成，我们将时间设为分钟数，以便显示清楚。&lt;/p&gt;
&lt;p&gt;完整代码如下：(taxi_sim.py)&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#! -*- coding: utf-8 -*-&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; random
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; collections
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; queue
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; argparse
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;DEFAULT_NUMBER_OF_TAXIS &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;DEFAULT_END_TIME &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;180&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;SEARCH_DURATION &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;TRIP_DURATION &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;DEPARTURE_INTERAVAL &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# time 是事件发生的仿真时间，proc 是出租车进程实例的编号，action是描述活动的字符串&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Event &lt;span style="color:#f92672"&gt;=&lt;/span&gt; collections&lt;span style="color:#f92672"&gt;.&lt;/span&gt;namedtuple(&lt;span style="color:#e6db74"&gt;&amp;#39;Event&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;time proc action&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 开始 出租车进程&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 每辆出租车调用一次taxi_process 函数，创建一个生成器对象，表示各辆出租车的运营过程。&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;taxi_process&lt;/span&gt;(ident, trips, start_time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;&amp;#39;&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; 每次状态变化时向创建事件，把控制权交给仿真器
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; :param ident: 出租车编号
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; :param trips: 出租车回家前的行程数量
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; :param start_time: 离开车库的时间
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; :return:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; &amp;#39;&amp;#39;&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; time &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;yield&lt;/span&gt; Event(start_time, ident, &lt;span style="color:#e6db74"&gt;&amp;#39;leave garage&amp;#39;&lt;/span&gt;) &lt;span style="color:#75715e"&gt;# 产出的第一个Event&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; i &lt;span style="color:#f92672"&gt;in&lt;/span&gt; range(trips): &lt;span style="color:#75715e"&gt;# 每次行程都会执行一遍这个代码块&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# 产出一个Event实例，表示拉到了乘客 协程在这里暂停 等待下一次send() 激活&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; time &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;yield&lt;/span&gt; Event(time, ident, &lt;span style="color:#e6db74"&gt;&amp;#39;pick up passenger&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# 产出一个Event实例，表示乘客下车 协程在这里暂停 等待下一次send() 激活&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; time &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;yield&lt;/span&gt; Event(time, ident, &lt;span style="color:#e6db74"&gt;&amp;#39;drop off passenger&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# 指定的行程数量完成后，for 循环结束，最后产出 &amp;#39;going home&amp;#39; 事件。协程最后一次暂停&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;yield&lt;/span&gt; Event(time, ident, &lt;span style="color:#e6db74"&gt;&amp;#39;going home&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# 协程执行到最后 抛出StopIteration 异常&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;compute_duration&lt;/span&gt;(previous_action):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;&amp;#39;&amp;#39;使用指数分布计算操作的耗时&amp;#39;&amp;#39;&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; previous_action &lt;span style="color:#f92672"&gt;in&lt;/span&gt; [&lt;span style="color:#e6db74"&gt;&amp;#39;leave garage&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;drop off passenger&amp;#39;&lt;/span&gt;]:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# 新状态是四处徘徊&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; interval &lt;span style="color:#f92672"&gt;=&lt;/span&gt; SEARCH_DURATION
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;elif&lt;/span&gt; previous_action &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;pick up passenger&amp;#39;&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# 新状态是开始行程&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; interval &lt;span style="color:#f92672"&gt;=&lt;/span&gt; TRIP_DURATION
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;elif&lt;/span&gt; previous_action &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;going home&amp;#39;&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; interval &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;raise&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ValueError&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;Unkonw previous_action: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;%s&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;%&lt;/span&gt; previous_action)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; int(random&lt;span style="color:#f92672"&gt;.&lt;/span&gt;expovariate(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;interval)) &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 开始仿真&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Simulator&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;__init__&lt;/span&gt;(self, procs_map):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;events &lt;span style="color:#f92672"&gt;=&lt;/span&gt; queue&lt;span style="color:#f92672"&gt;.&lt;/span&gt;PriorityQueue() &lt;span style="color:#75715e"&gt;# 带优先级的队列 会按时间正向排序&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;procs &lt;span style="color:#f92672"&gt;=&lt;/span&gt; dict(procs_map) &lt;span style="color:#75715e"&gt;# 从获取的procs_map 参数中创建本地副本，为了不修改用户传入的值&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;run&lt;/span&gt;(self, end_time):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;&amp;#39;&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; 调度并显示事件，直到时间结束
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; :param end_time: 结束时间 只需要指定一个参数
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; :return:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; &amp;#39;&amp;#39;&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# 调度各辆出租车的第一个事件&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; iden, proc &lt;span style="color:#f92672"&gt;in&lt;/span&gt; sorted(self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;procs&lt;span style="color:#f92672"&gt;.&lt;/span&gt;items()):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; first_event &lt;span style="color:#f92672"&gt;=&lt;/span&gt; next(proc) &lt;span style="color:#75715e"&gt;# 预激协程 并产出一个 Event 对象&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;events&lt;span style="color:#f92672"&gt;.&lt;/span&gt;put(first_event) &lt;span style="color:#75715e"&gt;# 把各个事件加到self.events 属性表示的 PriorityQueue对象中&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# 此次仿真的主循环&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; sim_time &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#75715e"&gt;# 把 sim_time 归0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; sim_time &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; end_time:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;events&lt;span style="color:#f92672"&gt;.&lt;/span&gt;empty(): &lt;span style="color:#75715e"&gt;# 事件全部完成后退出循环&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(&lt;span style="color:#e6db74"&gt;&amp;#39;*** end of event ***&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;break&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; current_event &lt;span style="color:#f92672"&gt;=&lt;/span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;events&lt;span style="color:#f92672"&gt;.&lt;/span&gt;get() &lt;span style="color:#75715e"&gt;# 获取优先级最高(time 属性最小)的事件&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; sim_time, proc_id, previous_action &lt;span style="color:#f92672"&gt;=&lt;/span&gt; current_event &lt;span style="color:#75715e"&gt;# 更新 sim_time&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(&lt;span style="color:#e6db74"&gt;&amp;#39;taxi:&amp;#39;&lt;/span&gt;, proc_id, proc_id &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39; &amp;#39;&lt;/span&gt;, current_event)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; active_proc &lt;span style="color:#f92672"&gt;=&lt;/span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;procs[proc_id] &lt;span style="color:#75715e"&gt;# 从self.procs 字典中获取表示当前活动的出租车协程&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; next_time &lt;span style="color:#f92672"&gt;=&lt;/span&gt; sim_time &lt;span style="color:#f92672"&gt;+&lt;/span&gt; compute_duration(previous_action)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;try&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; next_event &lt;span style="color:#f92672"&gt;=&lt;/span&gt; active_proc&lt;span style="color:#f92672"&gt;.&lt;/span&gt;send(next_time) &lt;span style="color:#75715e"&gt;# 把计算得到的时间发送给出租车协程。协程会产出下一个事件，或者抛出 StopIteration&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;except&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;StopIteration&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;del&lt;/span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;procs[proc_id] &lt;span style="color:#75715e"&gt;# 如果有异常 表示已经退出， 删除这个协程&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;events&lt;span style="color:#f92672"&gt;.&lt;/span&gt;put(next_event) &lt;span style="color:#75715e"&gt;# 如果没有异常，把next_event 加入到队列&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt;: &lt;span style="color:#75715e"&gt;# 如果超时 则走到这里&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; msg &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;*** end of simulation time: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt; event pendding ***&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(msg&lt;span style="color:#f92672"&gt;.&lt;/span&gt;format(self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;events&lt;span style="color:#f92672"&gt;.&lt;/span&gt;qsize()))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;main&lt;/span&gt;(end_time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;DEFAULT_END_TIME, num_taxis&lt;span style="color:#f92672"&gt;=&lt;/span&gt;DEFAULT_NUMBER_OF_TAXIS,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; seed&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;None&lt;/span&gt;):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;&amp;#39;&amp;#39;初始化随机生成器，构建过程，运行仿真程序&amp;#39;&amp;#39;&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; seed &lt;span style="color:#f92672"&gt;is&lt;/span&gt; &lt;span style="color:#f92672"&gt;not&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;None&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; random&lt;span style="color:#f92672"&gt;.&lt;/span&gt;seed(seed) &lt;span style="color:#75715e"&gt;# 获取可复现的结果&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# 构建taxis 字典。值是三个参数不同的生成器对象。&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; taxis &lt;span style="color:#f92672"&gt;=&lt;/span&gt; {i: taxi_process(i, (i &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;) &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;, i&lt;span style="color:#f92672"&gt;*&lt;/span&gt;DEPARTURE_INTERAVAL)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; i &lt;span style="color:#f92672"&gt;in&lt;/span&gt; range(num_taxis)}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; sim &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Simulator(taxis)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; sim&lt;span style="color:#f92672"&gt;.&lt;/span&gt;run(end_time)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; __name__ &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;__main__&amp;#39;&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; parser &lt;span style="color:#f92672"&gt;=&lt;/span&gt; argparse&lt;span style="color:#f92672"&gt;.&lt;/span&gt;ArgumentParser(description&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;Taxi fleet simulator.&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; parser&lt;span style="color:#f92672"&gt;.&lt;/span&gt;add_argument(&lt;span style="color:#e6db74"&gt;&amp;#39;-e&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;--end-time&amp;#39;&lt;/span&gt;, type&lt;span style="color:#f92672"&gt;=&lt;/span&gt;int,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; default&lt;span style="color:#f92672"&gt;=&lt;/span&gt;DEFAULT_END_TIME,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; help&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;simulation end time; default=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;%s&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;%&lt;/span&gt; DEFAULT_END_TIME)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; parser&lt;span style="color:#f92672"&gt;.&lt;/span&gt;add_argument(&lt;span style="color:#e6db74"&gt;&amp;#39;-t&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;--taxis&amp;#39;&lt;/span&gt;, type&lt;span style="color:#f92672"&gt;=&lt;/span&gt;int,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; default&lt;span style="color:#f92672"&gt;=&lt;/span&gt;DEFAULT_NUMBER_OF_TAXIS,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; help&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;number of taxis running; default = &lt;/span&gt;&lt;span style="color:#e6db74"&gt;%s&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;%&lt;/span&gt; DEFAULT_NUMBER_OF_TAXIS)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; parser&lt;span style="color:#f92672"&gt;.&lt;/span&gt;add_argument(&lt;span style="color:#e6db74"&gt;&amp;#39;-s&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;--seed&amp;#39;&lt;/span&gt;, type&lt;span style="color:#f92672"&gt;=&lt;/span&gt;int, default&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;None&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; help&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;random generator seed (for testing)&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; args &lt;span style="color:#f92672"&gt;=&lt;/span&gt; parser&lt;span style="color:#f92672"&gt;.&lt;/span&gt;parse_args()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; main(args&lt;span style="color:#f92672"&gt;.&lt;/span&gt;end_time, args&lt;span style="color:#f92672"&gt;.&lt;/span&gt;taxis, args&lt;span style="color:#f92672"&gt;.&lt;/span&gt;seed)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;运行程序，&lt;/p&gt;</description></item></channel></rss>