接触 PHP 不久,正在学习。现在碰到了这么一个问题。
有一批数据需要读取本地文件,并根据读取出来的每个 id 来请求 API 获取值,然后把值写入数据库。不可避免的用到了 foreach。
但是每次运行一会的时候,浏览器就提示 500---Internal Server Error 错误。php 代码也加上了 set_time_limit(0);ini_set('memory_limit', '-1')。
那么请问,这种情况是因为什么原因呢?是浏览器有默认的超时时间吗,脚本长时间不返回,浏览器就默认给超时了?还是因为超出了内存限制,给中断了?
大家碰到这种需要长时间处理大量数据的时候,是怎么解决的呢?因为是自学,所以没有人指点。有没有函数或者办法,可以解决以下 2 个问题。
1:浏览器超时(可能我描述不准确,但是说的就是浏览器获取不到返回值默认 500 )
2:这种循环太多了,内存肯定不够用的。那么是否可以随用随丢?
1
jhdxr 2018-03-26 00:15:24 +08:00 1
1. 超时不光在 php 这有限制,web server 那同样可能有限制。当然这种场景你现在这么处理的做法可以说就是错的,正确做法(之一)是把任务写到一个队列里去,然后另外在命令行里开一个专门读取然后处理。
2. 可以。文件读取参考 fopen 及相关函数,避免将文件一次性读入内存中。部分场景可以考虑用 generator 来减少内存的使用。占大量内存的数组在不需要时可以手动 unset,这样 GC 就会及时回收了。 |
3
Weny 2018-03-26 00:25:20 +08:00
队列
|
4
akira 2018-03-26 00:28:54 +08:00 1
长时间运行的话,在 php 这边先提前响应数据给页面,然后继续执行后续逻辑代码。
参考 https://www.jianshu.com/p/398792cf0ed5 但是在你这个情况里面,个人感觉不是这个问题,更多的像是你代码出错了,检查下错误日志吧 |
5
root123 2018-03-26 00:35:56 +08:00 1
这种场景就不应该用浏览器去执行,是错的。
1、用 cli 守护进程,如果要提高效率就的配合 pcntl_fork 子进程。 2、用 while (!feof($file)) 分段读取 |
6
lsido 2018-03-26 00:51:41 +08:00 via iPhone
这种场景就应该用 Python,捂脸捂脸捂脸捂脸(手动滑稽)
|
7
swuhvxee OP @akira 代码没错的,500 中断之前,所有的数据处理全部正确,500 之后的数据处理如果分批次执行也正确。应该不是代码的问题
|
9
shiji 2018-03-26 02:49:06 +08:00
这种情况我一般都是直接在终端里运行 PHP。
|
10
DavidNineRoc 2018-03-26 07:13:31 +08:00 via Android
PHP 生成器了解一下
|
11
mcfog 2018-03-26 07:55:47 +08:00 via Android
你应该先学会开 /看 /查错误日志
|
12
linzhoulxyz 2018-03-26 08:38:10 +08:00
先查下日志是什么原因造成的 500
|
13
solupro 2018-03-26 11:35:03 +08:00
可以试试加上
ignore_user_abort |
14
silencefent 2018-03-26 11:37:45 +08:00 1
用命令行 php path/index.php XXX/XXX/api 执行 php 方法
|
15
dangyuluo 2018-03-26 12:47:07 +08:00
beanstalkd,搞个伺服程序
|
16
yytsjq 2018-03-26 13:15:37 +08:00
php-fpm 的 request_terminate_timeout 太小?
|
17
eslizn 2018-03-26 13:18:28 +08:00
cli 了解一下
|
18
xuechaoc 2018-03-26 15:40:45 +08:00 1
长时间运行的脚本不应该出现在 web 请求里面,建议使用消息队列等异步方式。或者直接在终端运行脚本。
另外 500 错误一般也不是由于超时导致的,执行时间过长导致的超时,nginx 会返回错误码 504 Gateway Time Out |
19
qce7 2018-03-26 16:56:00 +08:00
500---Internal Server Error
这是代码写错了,开启一下 error_display=on; |
20
swuhvxee OP @shiji
@DavidNineRoc @silencefent @eslizn 好的,感谢解惑 @qce7 哥,虽然我感谢你的回答,但是你的回答是全部答案里最不靠谱最水的一个。代码错没错我能不知道吗 |
21
joeke 2018-03-26 18:43:21 +08:00
可以尝试一下 迭代器啊 ,占用内存小,再加一个 set_time_limit(0)
|
22
vincenttone 2018-03-26 18:54:55 +08:00
感觉楼主的应用是实时渲染,但是又有大量的 IO 请求。实际上可以做成异步,crontab 做个定时。
关于 foreach 的停止,可能是超时或者异常引起的,如果是 php7,可以用 try catch 捕获来防止这种问题。 如果数量非常多的话,可以考虑对文件内容做个分割,通过 fork 子进程来处理。 如果做成异步轻量级的应用,可以考虑用 redis 做个缓存或者直接文件缓存。 |
23
qce7 2018-03-27 09:18:41 +08:00
nginx 500,你看你现在连是哪行代码抛出异常都不清楚,就去优化,这难道不应该去开错误显示或者日志吗吗。。。
|
24
NowTime 2018-04-03 10:49:53 +08:00 via Android
命令行了解下,你这种效率太低了
写好代码,比如保存为 run.php 执行命令 php run.php |