作者你好,提个优化内存消耗和加载字典时间的建议
createlinux opened this issue · comments
如果能写成单例模式就好了,结合swoole让实例常驻内存。
然后搭建一个swoole api应用。使用的时候请求api接口,因为实例常驻内存,不用每次都初始化,所以内存消耗和加载速度非常的快。
我测了一下:内存消耗和时间花费都在加载字典上面。停词花费的时间并不多。
我把搜狗的几个词库加进去,10万3000行左右。加载速度特别慢,其他的步骤还好。
- 内存使用:0.67919158935547|初始化之前| 花费时间:0
- 内存使用:79.676719665527|结巴初始化完成| 花费时间:0.12999987602234
- 内存使用:82.161094665527|Finalseg初始化完成| 花费时间:0.14949989318848
- 内存使用:109.49954223633|JiebaAnalyse初始化完成| 花费时间:0.33049988746643
- 内存使用:207.0001373291|加载字典完成| 花费时间:2.8549997806549
- 内存使用:207.19972229004|加载停词完成| 花费时间:2.8864998817444
- 内存使用:207.19972229004|0 | 花费时间:2.8864998817444
- 内存使用:208.78179931641|1| 花费时间:3.0029997825623
- 内存使用:208.78179931641|2| 花费时间:3.0714998245239
- 内存使用:208.78179931641|3| 花费时间:3.1409997940063
- 内存使用:208.78179931641|4| 花费时间:3.2099997997284
- 内存使用:208.78179931641|5| 花费时间:3.2795000076294
- 内存使用:208.78179931641|6| 花费时间:3.3494999408722
- 内存使用:208.78179931641|7| 花费时间:3.4249999523163
- 内存使用:208.78179931641|8| 花费时间:3.4954998493195
- 内存峰值:224.774879455579| 花费时间:3.5649998188019
解决方法已经出来了:
使用swoole搭建一个http服务器,因为是常驻内存,所以加载字典步骤在服务器启动的时候就已经加载好了。然后查询的时候请求接口就Ok了。速度杠杠的。这个是php终极解决方案。
@GlaryJoker 感謝,我把這個 issue 留著,讓大家可以參考一下作為一種 solution
贴个示例代码
`require_once dirname(DIR).'/vendor/autoload.php';
use Fukuball\Jieba\Jieba;
use Fukuball\Jieba\JiebaAnalyse;
use Fukuball\Jieba\Finalseg;
//Jieba::init(array('mode'=> 'Default','dict' => 'big'));
Jieba::init(array('mode'=>'Search Engine','dict'=>'small'));
Finalseg::init();
JiebaAnalyse::init();
$dictPath = dirname(DIR). '/dict/text_dict.txt';
$stopDictPath = dirname(__DIR__).'/dict/chinese_sw.txt';
Jieba::loadUserDict($dictPath);
JiebaAnalyse::setStopWords($stopDictPath);
$topLimit = 20;
$http = new swoole_http_server("127.0.0.1",9501);
$http->on("request",function($request,$response) use ($topLimit){
$response->header("Content-Type", "application/json; charset=utf-8");
$title = $request->post['title'] ?? 'none';
$content = $request->post['content'] ?? 'none';
$token = $request->post['token'] ?? 'none';
$content = urldecode($content);
$title = urldecode($title);
if($token === 'none') $response->end(json_encode([]));
if($title !== 'none' && mb_strlen($title) > 10){
$titleTags = implode(',',array_keys(JiebaAnalyse::extractTags($title, $topLimit)));
}
if($content !== 'none' && mb_strlen($content) > 15){
$contentTags = implode(',',array_keys(JiebaAnalyse::extractTags($content,$topLimit)));
}
$response->write(json_encode([
'title' => $titleTags ?? 'none',
'content' => $contentTags ?? 'none',
'ini_memory' => ini_get('memory_limit'),
'usage' => memory_get_usage()/1024/1024
],JSON_UNESCAPED_UNICODE));
//$response->end();
});
$http->start();`
nginx 配置
`server {
listen 9583;
server_name www.example.com;
large_client_header_buffers 4 128k;
location / {
proxy_http_version 1.1;
proxy_set_header Connection "keep-alive";
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Transfer-Encoding: "gzip";
proxy_pass http://127.0.0.1:9501;
}
}
`
php代码以守护进程模式运行,速度杠杠的。
如何热加载用户自己的词典?
如何热加载用户自己的词典?
可以把字典放redis里,需要改一下源代码,自己可以fork一份
解决方法已经出来了:
使用swoole搭建一个http服务器,因为是常驻内存,所以加载字典步骤在服务器启动的时候就已经加载好了。然后查询的时候请求接口就Ok了。速度杠杠的。这个是php终极解决方案。
我之前也弄了个简单的服务,基于swoole让字典常驻内存。
https://github.com/wyq2214368/laravel-jieba
@wyq2214368 问一下,为什么要controller有构造方法才能在常驻内存?我试了下,controller没有构造方法就没有常驻内存了。