并发任务分配问题

这是在工作中遇到的实际问题和解决过程。问题已经被抽象成并发任务的分配问题。

问题

如果有 n 组数据均分给 m 个处理器处理,那么每个处理器分到的数据是 \(\lceil \frac{n}{m} \rceil\) 。如果n组数据的类型有差异,其中有a组是一类数据,剩余 n-a 组是另一类数据。只有同类数据才能被一次性处理,那么该如何分配?

这个问题在现实中是存在的。比如HTTP并发请求处理一些数据。数据被批量送来,但类型不一样。为了节省耗时,我们希望并发处理这些不同的数据。并发数是确定好的。现在需要计算每个请求处理的数量,以便我们能给每一个请求打包数据。

求解

n 组数据交给 m 个处理器处理,每个处理器最多分到 \(\lceil \frac{n}{m} \rceil\) 组数据,这是毫无疑问的。如果 n 组数据中有a组是一类数据,n-a组是另一类数据。同类数据必须分配到同一个处理器。那么a类数据得到的处理器的数量是 \(\lceil \frac {a} {\lceil \frac{n}{m} \rceil} \rceil \),b类得到的处理器的数量是 \(\lceil \frac {n-a} {\lceil \frac{n}{m} \rceil} \rceil \)。我们现在其实需要考虑它们总共需要的处理器数量和m的关系。原有的m个处理器是否满足这种需求?如果不满足,需要多少个处理器才能满足?

即,求 \(( \lceil \frac {a}{\lceil \frac{n}{m} \rceil} \rceil +\lceil \frac {n-a} {\lceil \frac{n}{m} \rceil} \rceil ) \) 和 m的关系。

对于上面的问题,我们的存在一些已知的前提条件:

  1. m, m 为正整数
  2. \(n \leq m\)

根据上面已知的条件,我们可以得出一些引理:

  1. \(\lceil \frac {n}{m} \rceil \geq \frac {n}{m} \)
  2. \( \lceil \frac {n}{m} \rceil \leq \frac {n}{m} + \frac {m-1}{m} \)

因此,容易得出\(( \lceil \frac {a}{\lceil \frac{n}{m} \rceil} \rceil +\lceil \frac {n-a} {\lceil \frac{n}{m} \rceil} \rceil ) \geq \lceil \frac {n}{\lceil \frac {n}{m} \rceil} \rceil \geq m \)

即数据类型分成两种的时候所需要的处理器数量是大于等于m的,原先的处理器个数可能不够用了。那么多少才够用?这是现在需要考虑的问题。

容易得出,\( ( \lceil \frac {a}{\lceil \frac{n}{m} \rceil} \rceil +\lceil \frac {n-a} {\lceil \frac{n}{m} \rceil} \rceil ) \leq \lceil \frac {am}{n}\rceil + \lceil \frac {(n-a)m} {n} \rceil \)

根据上面的引理可以得出 \( \lceil \frac {am}{n}\rceil + \lceil \frac {(n-a)m} {n} \rceil \leq \frac {am}{n} + \frac {n-1}{n} + \frac {(n-a)m} {n} + \frac {n-1}{n} = n+2-\frac{2}{n} \)

由已知条件可以知道,\( ( \lceil \frac {a}{\lceil \frac{n}{m} \rceil} \rceil +\lceil \frac {n-a} {\lceil \frac{n}{m} \rceil} \rceil )\) 是正整数,因此可以将 \( n+2-\frac{2}{n} \)向下取整为\(n+1\)。

即需要n+1个处理器才能满足要求。

因此遇到这种问题的时候,要么增加一个处理器,要么计算每个处理器能处理的数量的时候在原先处理器数量减一的基础上计算。

你可能还喜欢下面这些文章

股票获取接口

最近开始研究股票了,自己一个一个的去看,几千支股票完全看不过来啊,想着自己写一个程序,让程序来看股票吧!股票接口首先我们需要得到所有的股票代码,好在已经有网页帮我们列出了所有的股票名称和代码,地址是:http://quote.eastmoney.com/stocklist.html通过这个页面,就可以抓取了。抓取之后我们就可以存入mysql中,每一个股票可以存一张表,而每一张表中则可以存入股票的动态数据。这里我们只能获取到一些最简单的数据,一些更加详细的数据还需要获取,这里需要使用一个腾讯财经的接口http://qt.gtimg.cn/q=sz000858该接口为获取五粮液的股票数据,返回结果

CGI与FastCGI是什么

当我们在谈到cgi的时候,我们在讨论什么最早的Web服务器简单地响应浏览器发来的HTTP请求,并将存储在服务器上的HTML文件返回给浏览器,也就是静态html。事物总是不 断发展,网站也越来越复杂,所以出现动态技术。但是服务器并不能直接运行 php,asp这样的文件,自己不能做,外包给别人吧,但是要与第三做个约定,我给你什么,然后你给我什么,就是握把请求参数发送给你,然后我接收你的处 理结果给客户端。那这个约定就是 common gateway interface,简称cgi。这个协议可以用vb,c,php,python 来实现。cgi只是接口协议,根本不是什么语言。下面图可以看到流程WEB服

使用php curl 的并发能力可以做什么

在php中,没有多线程让编程变得简单。但在一些需要并发提升性能的场景下,显得有些无能为力,比如发起一些http请求。但好在curl扩展可以让我们“并发”去请求网络资源。利用这个特点,我们能做很多有趣的事情。最基础的,并发请求网络资源,提升处理速度。并发访问代码<?phpclass ConcurrencyHTTP { private $_requests; private $_callbacks; private $_currentIndex = 0; public function get($url, $header = array(), $timeout = 3

漫话中文自动分词和语义识别(上):中文分词算法

记得第一次了解中文分词算法是在 Google 黑板报 上看到的,当初看到那个算法时我彻底被震撼住了,想不到一个看似不可能完成的任务竟然有如此神奇巧妙的算法。最近在詹卫东老师的《中文信息处理导论》课上再次学到中文分词算法,才知道这并不是中文分词算法研究的全部,前前后后还有很多故事可讲。在没有建立统计语言模型时,人们还在语言学的角度对自动分词进行研究,期间诞生了很多有意思的理论。中文分词的主要困难在于分词歧义。“结婚的和尚未结婚的”,应该分成“结婚/的/和/尚未/结婚/的”,还是“结婚/的/和尚/未/结婚/的”?人来判断很容易,要交给计算机来处理就麻烦了。问题的关键就是,“和尚未”里的“和尚”也是

我是一个线程

来自:码农翻身(微信号:coderising)作者:IBM刘欣我是一个线程,我一出生就被编了个号: 0x3704,然后被领到一个昏暗的屋子里, 这里我发现了很多和我一模一样的同伴。我身边的同伴0x6900待的时间比较长, 他带着沧桑的口气对我说:“我们线程的宿命就是处理包裹。把包裹处理完以后还得马上回到这里,否则可能永远回不来了。”我一脸懵懂,包裹,什么包裹?“不要着急,马上你就会明白了, 我们这里是不养闲人的。”果然,没多久,屋子的门开了, 一个面貌凶恶的家伙吼道:“0x3704 ,出来!”我一出来就被塞了一个沉甸甸的包裹,上面还有附带着一个写满了操作步骤的纸。“快去,把这个包裹处理了。”“

websocket协议详解

近来项目中使用websocket,于是来研究一番。websocket传输协议有两个部分,握手和数据传输握手GET / HTTP/1.1HOST: <IP>:<PORT> Sec-Websocket-Version: 13Sec-Websocket-Key: <KEY>Connection: keep-alive, UpgradeUpgrade: websocket之后服务端会返回类似下面的数据HTTP/1.1 101 Switching ProtocolsUpgrade: websocketConnection: UpgradeSec-WebSocket-A

布隆过滤器(bloom filter)介绍以及php和redis实现布隆过滤器实现方法

引言在介绍布隆过滤器之前我们首先引入几个场景。场景一在一个高并发的计数系统中,如果一个key没有计数,此时我们应该返回0。但是访问的key不存在,相当于每次访问缓存都不起作用了。那么如何避免频繁访问数量为0的key而导致的缓存被击穿?有人说, 将这个key的值置为0存入缓存不就行了吗?这是确实是一种解决方案。当访问一个不存在的key的时候,设置一个带有过期时间的标志,然后放入缓存。不过这样做的缺点也很明显:浪费内存和无法抵御随机key攻击。场景二在一个黑名单系统中,我们需要设置很多黑名单内容。比如一个邮件系统,我们需要设置黑名单用户,当判断垃圾邮件的时候,要怎么去做。比如爬虫系统,我们要记录下

ajax的核心,好好认识一下XMLHttpRequest

相信包括在我的绝大多数人都用jQuery的$.get(),$.post(),$.ajax()方法用的很爽了,关于其原生的请求却很少去发掘,很多时候(比如用html5开发app的时候),我并不再需要jQuery,弄明白XMLHttpRequest用原生的就能很好的处理ajax了。首先,由于我的js是通过jQuery入门的,所以才会有这篇文章。从new一个对象开始var xmlhttp = new XMLHttpRequest();之后的请求,读取,出错等等各种处理都在xmlhttp这个对象里面啦第一个GET请求get请求简单,最适合入门操作啦。之前new了一个xmlhttp对象,这次我们就要对它

Redis持久化

在一个高并发,但是数据量不大的系统中,使用Redis做数据库再好不过,结合Swoole,只需要很少的机器就能抗住很大的量。Redis大多数的应用可能都是当做缓存,当作为一个数据库用的时候,就必须要考虑持久化的问题了。持久化的意思就是将内存中的数据写到磁盘中,当再次重启之后,数据可以从磁盘中进行恢复,不会丢失。Redis持久化有两个策略,一个是RDB快照,一个AOF日志,不管是什么策略,最终的目的都是将数据保存在磁盘上,并不高深。只需要耐心的看看这两种策略,就能明白了。RDB快照从名字上我们就能知道这是RedisDB的缩写了,Redis快照是这样生成的,到了需要生成快照的时候,通过fork当前进

漫话中文自动分词和语义识别(下):句法结构和语义结构

这篇文章是漫话中文分词算法的续篇。在这里,我们将紧接着上一篇文章的内容继续探讨下去:如果计算机可以对一句话进行自动分词,它还能进一步整理句子的结构,甚至理解句子的意思吗?这两篇文章的关系十分紧密,因此,我把前一篇文章改名为了《漫话中文自动分词和语义识别(上)》,这篇文章自然就是它的下篇。我已经在很多不同的地方做过与这个话题有关的演讲了,在这里我想把它们写下来,和更多的人一同分享。什么叫做句法结构呢?让我们来看一些例子。“白天鹅在水中游”,这句话是有歧义的,它可能指的是“白天有一只鹅在水中游”,也可能指的是“有一只白天鹅在水中游”。不同的分词方案,产生了不同的意义。有没有什么句子,它的分词方案是

布隆过滤器(bloom filter)介绍以及php和redis实现布隆过滤器实现方法

引言

在介绍布隆过滤器之前我们首先引入几个场景。

场景一

在一个高并发的计数系统中,如果一个key没有计数,此时我们应该返回0。但是访问的key不存在,相当于每次访问缓存都不起作用了。那么如何避免频繁访问数量为0的key而导致的缓存被击穿?

有人说, 将这个key的值置为0存入缓存不就行了吗?这是确实是一种解决方案。当访问一个不存在的key的时候,设置一个带有过期时间的标志,然后放入缓存。不过这样做的缺点也很明显:浪费内存和无法抵御随机key攻击。

场景二

在一个黑名单系统中,我们需要设置很多黑名单内容。比如一个邮件系统,我们需要设置黑名单用户,当判断垃圾邮件的时候,要怎么去做。比如爬虫系统,我们要记录下来已经访问过的链接避免下次访问重复的链接。

在邮件很少或者用户很少的情况下,我们用普通数据库自带的查询就能完成。在数据量太多的时候,为了保证速度,通常情况下我们会将结果缓存到内存中,数据结构用hash表。这种查找的速度是O(1),但是内存消耗也是惊人的。打个比方,假如我们要存10亿条数据,每条数据平均占据32个字节,那么需要的内存是64G,这已经是一个惊人的大小了。

一种解决思路

能不能有一种思路,查询的速度是O(1),消耗内存特别小呢?前辈门早就想出了一个很好的解决方案。由于上面说的场景判断的结果只有两种状态(是或者不是,存在或者不存在),那么对于所存的数据完全可以用位来表示。数据本身则可以通过一个hash函数计算出一个key,这个key是一个位置,而这个key所对的值就是0或者1(因为只有两种状态),如下图:

(更多…)

你可能还喜欢下面这些文章

gcc/g++编译参数详解

编译步骤gcc 与 g++ 分别是 gnu 的 c & c++ 编译器。gcc/g++ 在执行编译工作的时候,总共需要4步:预处理,生成 .i 的文件将预处理后的文件转换成汇编语言, 生成文件 .s 有汇编变为目标代码(机器代码)生成 .o 的文件连接目标代码, 生成可执行程序 参数详解-x language filename参数含义为指定文件所使用的语言。根据约定,C语言的后缀名称为".c",而 C++ 的后缀名为".cpp"或".cc",但如果你的源代码后缀不约定的那几种,那么需要使用-x参数来指定文件所使用的语言。这个参数对他后面的文件名都起作用。 可以使用的参数吗有下面的这些:

iterm2 使用 rz、sz 的方法

如果没有额外的设置,iterm2 使用 rzsz 的时候会卡在这个时候就需要使用iterm2提供的trigger来实现rzsz的功能。第一步:本机安装rzsz使用rzsz之前本地也需要安装如果没有安装brew,请先安装brew,mac必备的包管理器!第二步:创建发送和接收脚本发送文件的脚本如下,可以复制下面的内容,保存在 /usr/local/bin/iterm2-send-zmodem.sh中。接收文件的脚本如下,同样可以复制保存在/usr/local/bin/iterm2-recv-zmodem.sh第三步:设置Triggerteigger需要设置两个,一个实发送文件的trigger,一个

使用sublime+platuml高效画图

程序员难免要经常画流程图,状态图,时序图等。以前经常用 visio 画,经常为矩形画多大,摆放在哪等问题费脑筋。有时候修改文字后,为了较好的显示效果不得不再去修改图形。今天介绍的工具是如何使用 Sublime + PlantUML 的插件画流程图,状态图,时序图等。这是一种程序员看了就会爱上的画图方式:自然,高效。什么是 PlantUMLPlantUML 是一个画图脚本语言,用它可以快速地画出:时序图流程图用例图状态图组件图简单地讲,我们使用 visio 画图时需要一个一个图去画,但使用 PlantUML 只需要用文字表达出图的内容,然后就可以直接生成图片。看一个最简单的例子:软件安装这些软件

Go入门:六、常用标准库

这是我的Go学习的第六篇笔记,也是Go入门的最后一篇笔记。在大多数语言中,了解了变量和数据类型,流程控制,函数,面向对象,再加上标准库,就可以用这门语言去写一些项目了。首先让我想想,在工作中通常会用语言频繁处理什么问题或者处理什么数据?最常见的应该是各种字符串操作,日期和时间,读写文件、socket等IO相关的操作!字符串处理 — StringsString提供了一组处理字符串的操作,常用的有:判断一个字符串是否在另一个字符串中分割字符串为[]string和组合[]string为一个字符串字符串替换...太多了,就不一一列举了,这里列出一些常用的字符串操作。字符串判断字符串分割与合并字符串转换

Go入门:四、面向对象

这是我的Go学习笔记的第四篇,面向对象!现代语言几乎都会面向对象进行了支持!当然,Go也具备面向对象的特性!我的语言学习过程一般分为下面几个:1. 变量和数据类型2. 流程控制方法3. 函数声明和调用4. 面向对象5. 语言特性6. 标准库Go语言中的面向对象有点特殊。在Go语言里面,没有显式的class、extends等面向对象语言经常使用的关键词,但是却有面向对象的特性。看看Go怎么实现的把!创建一个类按照我的理解,类实际上就是某种模板,这个模板里面含有有限多个属性和方法。在Go里面,定义这个模板的语法使用type来实现!比如单个int类型可以构成一个类(没错,你甚至可以在int数据类型上

signal函数详解

signal作用是为信号注册一个处理器。这里的“信号”是软中断信号,这种信号来源主要有三种:程序错误:比如除0,非法内存访问。外部信号:终端Ctrl-C产生的SIGINT信号,定时器产生的SIGALERM。显示请求:kill函数发送的任意信号。当kill一个进程的时候,默认会发送SIGTERM信号,此时这个信号只有默认处理操作(SIG_DFL),直接中断进程执行。如果此时该进程正在执行一个任务,直接终止该进程会导致任务没有完成。这个时候为SIGTERM信号注册一个信号处理函数就十分有必要。介绍参数sig要设置信号处理函数的信号。它可以是实现定义值或下例值之一:SIGABRTSIGFPESIGI

C++动态内存管理

C++中,动态内存管理是通过一对运算符来完成:new 和 delete。new操作符在内存中为对象分配空间并返回一个指向该对象的指针,delete接收一个动态对象的指针,销毁该对象,并释放与之相关的内存。手动管理内存看起来只有这两个操作,似乎很轻松,但实际上这是一件非常繁琐的事情,分配了内存但没有释放内存的场景发生的概率太大了!回想一下,你有多少次打开抽屉却没关上,拿出来的护肤品擦完脸之后却忘了放回去,吃完饭却忘了洗碗。类似这种没有收尾的事情我做的太多了。(以上这些都是在实际生活中我爱人批评我的点)我连这种明面上的事情都能忘记收尾,何况分配内存!所以为了世界和平,我放弃了手动管理内存。好在C+

C++右值引用和移动

Attention:this blog is a translation of https://www.internalpointers.com/post/c-rvalue-references-and-move-semantics-beginners ,which is posted by @internalpoiners.一、前言在我的前一篇文章里,我解释了右值背后的逻辑。核心的思想就是:在C++中你总会有一些临时的、生命周期较短的值,这些值无论如何你都无法改变。令人惊喜的是,现代C++(通常指C++0x或者更高的版本)引入了右值引用(rvalue reference)的概念:它是一个新的

C++入门:三、函数

这是我学习C++的第三篇笔记,函数。我的学习路径是现在学习的是函数的声明、定义、调用等相关知识。函数声明和定义函数的声明包含返回类型,函数名字,0个或者多个形参,无函数体,通常在头文件中对函数进行声明。函数的定义包含返回类型,函数名字,0个或多个形参,以及函数体。比如写一个求阶乘的函数,可以写成下面这样写一些简单的函数大多数语言都差不多,不过可惜每种语言或多或少都有自己的特色,这是比较令人头秃的地方。函数的参数函数可以带有0或多个参数,每个参数都需要声明类型。参数传递可以传值和传引用。如果形参是引用类型,那么它将绑定到对应的实参中,我们成为传引用。否则,将会把实参的值拷贝后赋值给形参,我们成为

如何选择特征

特征工程是数据分析中最耗时间和精力的一部分工作,它不像算法和模型那样是确定的步骤,更多是工程上的经验和权衡。因此没有统一的方法。这里只是对一些常用的方法做一个总结。本文关注于特征选择部分。后面还有两篇会关注于特征表达和特征预处理。1. 特征的来源在做数据分析的时候,特征的来源一般有两块,一块是业务已经整理好各种特征数据,我们需要去找出适合我们问题需要的特征;另一块是我们从业务特征中自己去寻找高级数据特征。我们就针对这两部分来分别讨论。2.  选择合适的特征我们首先看当业务已经整理好各种特征数据时,我们如何去找出适合我们问题需要的特征,此时特征数可能成百上千,哪些才是我们需要的呢?第一