【发布时间】:2017-02-15 18:01:29
【问题描述】:
作为基于 Laravel 的应用程序的一部分,我正在尝试编写一个 PHP 脚本来获取某些数据,即不断更新,来自在网络上关于某些产品,确切地说是书籍。
问题:
图书由 ISBN(一个 10 位标识符)标识。前 9 位可以是 0-9,最后一位可以是 0-9 或 X。但是,最后一位是校验位,是根据前 9 位计算的,因此实际上只有 1 个可能的数字最后一位。
既然如此,我们就得出:
10*10*10*10*10*10*10*10*10*1 = 1,000,000,000
数字正确的 ISBN。如果我将搜索限制在英文书籍上,我可以做得更好,因为它们只会包含 0 或 1 作为第一个数字。因此我会得到:
2*10*10*10*10*10*10*10*10*1 = 200,000,000
数字正确的 ISBN。
现在,对于每个 ISBN,我都有 3 个 http 请求来获取数据,每个请求大约需要 3 秒才能完成。因此:
3seconds*3requests*200,000,000ISBNs = 1,800,000,000 seconds
1,800,000,000seconds/60seconds/60minutes/24hours/365days = ~57 years
希望在 57 年后,不再有书之类的东西,这种算法也将过时。
实际上,由于我关注的数据在不断变化,因此要使该算法有用,它必须在几天内完成每次通过(理想情况下为 2 到 7 天)。
因此问题是如何优化该算法以将其运行时间从 57 年缩短到仅一周?
可能的解决方案:
1) 您会注意到的第一件事是,虽然有 200,000,000 个可能的 ISBN,但实际存在的 ISBN 却远不及那么多,这意味着该算法的大多数将 花时间 在错误的 ISBN 上发出 http 请求(我可以在第一次失败的 http 请求后转到下一个 ISBN,但仅此一项并不足以显着降低时间)。因此,解决方案 1 将是获取/购买/下载一个数据库,其中已经包含一个正在使用的 ISBN 列表,从而显着减少了要搜索的 ISBN 数量。 p>
我对解决方案1的问题是新书不断出版,我希望在算法再次运行时继续阅读新书。使用现有书籍的数据库仅适用于数据库创建时最新的书籍。 (一个潜在的解决办法是提供一个不断更新他们的数据库的服务,让我每周下载一次,但这似乎不太可能,而且我真的希望通过编程来解决这个问题!)
2) 虽然这个算法需要很长时间才能运行,但大多数时候它实际上只是闲置等待等待 http 响应。因此,一种选择似乎是使用 Threads。
如果我们进行数学运算,我认为等式将如下所示:
(numISBNs/numThreads)*secondsPerISBN = totalSecondsToComplete
如果我们隔离 numThreads:
numThreads = (numISBNs * secondsPerISBN) / totalSecondsToComplete
如果我们的阈值是一周,那么:
totalSecondsToComplete = 7days * 24hrs * 60min * 60sec = 604,800seconds
numISBNs = 200,000,000
secondsPerISBN = 3
numThreads = (200,000,000 * 3) / 604,800
numThreads = ~992
所以 992 线程必须同时运行才能使其工作。这是在 DigitalOcean 服务器上运行的合理线程数吗?我的 mac 现在说它正在运行超过 2000 个线程,所以这个数字实际上是可以管理的。
我的问题:
1) 992 是否是在 DigitalOcean 服务器上运行的合理线程数?
2) 由于每个 http 请求完全独立于任何其他请求,因此是否有更有效的方法来异步执行此算法?在等待所有 http 请求返回时保持 CPU 忙碌的最佳方法是什么?
3) 是否有我应该为此寻找的特定服务可能有助于实现我正在寻找的东西?
【问题讨论】:
-
很好的问题...但可能在错误的地方被问到。我建议您与 DigitalOcean 联系并听取他们的意见!
-
有没有办法一次请求多个isbn?
-
解决方案 1 中提到的数据库中有多少个 ISBN?即使这个数字是所有可能的 ISBN 排列的 50%,根据您的估计,解决方案 1 仍需要 28.5 年。除非像 Ryan Vincent 提到的启发式方法大大减少了搜索空间,否则解决方案 2 似乎是您的最佳选择。
-
@RyanVincent 根据维基百科 isbns 不是随机生成的,它有一些逻辑。这就是我如何能够假设所有英文书籍的第一个数字都是 0 或 1。问题是 ISBN 的其他部分不太容易弄清楚,甚至可能包含可变位数。例如,ISBN 的一部分是出版商代码,维基百科说,人们可以花几千美元购买一份包含 900,000 个有效出版商代码的当前列表......你明白为什么这不会那么容易......
-
@Svea 我同意解决方案 2 似乎是最好的选择。我的问题是,实现它的最佳方法是什么?我应该使用线程吗?分叉大量进程?有其他方法吗?
标签: php multithreading algorithm laravel curl-multi