逗比欢乐多

逗比欢乐多 查看完整档案

北京编辑西北工业大学  |  计算机科学技术 编辑  |  填写所在公司/组织 starriv.com 编辑
编辑
_ | |__ _ _ __ _ | '_ \| | | |/ _` | | |_) | |_| | (_| | |_.__/ \__,_|\__, | |___/ 个人简介什么都没有

个人动态

逗比欢乐多 评论了文章 · 2018-06-12

Electron应用使用electron-builder配合electron-updater实现自动更新

开发客户端一定要做的就是自动更新模块,否则每次版本升级都是一个头疼的事。
下面是Electron应用使用electron-builder配合electron-updater实现自动更新的解决方案。

1.安装 electron-updater 包模块

npm install electron-updater --save

2.配置package.json文件
2.1 为了打包时生成latest.yml文件,需要在 build 参数中添加 publish 配置。

  "build": {
    "productName": "***",//隐藏软件名称
    "appId": "**",//隐藏appid
    "directories": {
      "output": "build"
    },
    "publish": [
      {
        "provider": "generic",
        "url": "http://**.**.**.**:3002/download/",//更新服务器地址,可为空
      }
    ],
    "files": [
      "dist/electron/**/*"
    ],
    "dmg": {
      "contents": [
        {
          "x": 410,
          "y": 150,
          "type": "link",
          "path": "/Applications"
        },
        {
          "x": 130,
          "y": 150,
          "type": "file"
        }
      ]
    },
    "mac": {
      "icon": "build/icons/icon.icns",
      "artifactName": "${productName}_setup_${version}.${ext}"
    },
    "win": {
      "icon": "build/icons/icon.ico",
      "artifactName": "${productName}_setup_${version}.${ext}"
    },
    "linux": {
      "icon": "build/icons",
      "artifactName": "${productName}_setup_${version}.${ext}"
    }
  }

注意:配置了publish才会生成latest.yml文件,用于自动更新的配置信息;latest.yml文件是打包过程生成的文件,为避免自动更新出错,打包后禁止对latest.yml文件做任何修改。如果文件有误,必须重新打包获取新的latest.yml文件!!!

2.2 增加nsis配置(可省略)
nsis配置不会影响自动更新功能,但是可以优化用户体验,比如是否允许用户自定义安装位置、是否添加桌面快捷方式、安装完成是否立即启动、配置安装图标等。nsis 配置也是添加在 build 参数中。 详细参数配置可参见官方文档 nsis配置

"nsis": {
      "oneClick": true,
      "perMachine": true,
      "allowElevation": true,
      "allowToChangeInstallationDirectory": true,
      "createDesktopShortcut": true,
      "runAfterFinish": true,
      "installerIcon": "./build/icon.ico",
      "uninstallerIcon": "./build/icon.ico"
    },

3.配置主进程main.js文件(或主进程main中的index.js文件),引入 electron-updater 文件,添加自动更新检测和事件监听:
注意:一定要是主进程main.js文件(或主进程main中的index.js文件),否则会报错。
注意:这个autoUpdater不是electron中的autoUpdater,是electron-updater的autoUpdater,否则坑你没商量!

import { app, BrowserWindow, ipcMain } from 'electron'

// 注意这个autoUpdater不是electron中的autoUpdater
import { autoUpdater } from "electron-updater"
// 更新服务器地址,比如"http://**.**.**.**:3002/download/"
import {uploadUrl} from "../renderer/config/config";

// 检测更新,在你想要检查更新的时候执行,renderer事件触发后的操作自行编写
function updateHandle() {
  let message = {
    error: '检查更新出错',
    checking: '正在检查更新……',
    updateAva: '检测到新版本,正在下载……',
    updateNotAva: '现在使用的就是最新版本,不用更新',
  };
  const os = require('os');

  autoUpdater.setFeedURL(uploadUrl);
  autoUpdater.on('error', function (error) {
    sendUpdateMessage(message.error)
  });
  autoUpdater.on('checking-for-update', function () {
    sendUpdateMessage(message.checking)
  });
  autoUpdater.on('update-available', function (info) {
    sendUpdateMessage(message.updateAva)
  });
  autoUpdater.on('update-not-available', function (info) {
    sendUpdateMessage(message.updateNotAva)
  });

  // 更新下载进度事件
  autoUpdater.on('download-progress', function (progressObj) {
    mainWindow.webContents.send('downloadProgress', progressObj)
  })
  autoUpdater.on('update-downloaded', function (event, releaseNotes, releaseName, releaseDate, updateUrl, quitAndUpdate) {

    ipcMain.on('isUpdateNow', (e, arg) => {
      console.log(arguments);
      console.log("开始更新");
      //some code here to handle event
      autoUpdater.quitAndInstall();
    });

    mainWindow.webContents.send('isUpdateNow')
  });

  ipcMain.on("checkForUpdate",()=>{
      //执行自动更新检查
      autoUpdater.checkForUpdates();
  })
}

// 通过main进程发送事件给renderer进程,提示更新信息
function sendUpdateMessage(text) {
  mainWindow.webContents.send('message', text)
}

注:在添加自动更新检测和事件监听之后,在主进程createWindow中需要调用一下updateHandle()。如下图所示:
图片描述

4.在视图(View)层中触发自动更新,并添加自动更新事件的监听。
触发自动更新:

ipcRenderer.send("checkForUpdate");

监听自动更新事件:

  import { ipcRenderer } from "electron";
  ipcRenderer.on("message", (event, text) => {
            console.log(arguments);
            this.tips = text;
        });
        //注意:“downloadProgress”事件可能存在无法触发的问题,只需要限制一下下载网速就好了
        ipcRenderer.on("downloadProgress", (event, progressObj)=> {
            console.log(progressObj);
            this.downloadPercent = progressObj.percent || 0;
        });
        ipcRenderer.on("isUpdateNow", () => {
            ipcRenderer.send("isUpdateNow");
        });

注意:子进程中“downloadProgress”事件可能出现无法触发的问题,那是因为下载速度很快,就会跳过“downloadProgress”事件;只需要限制一下本地下载网速就好了!

为避免多次切换页面造成监听的滥用,切换页面前必须移除监听事件:

//组件销毁前移除所有事件监听channel
        ipcRenderer.removeAll(["message", "downloadProgress", "isUpdateNow"]);//remove只能移除单个事件,单独封装removeAll移除所有事件

5.项目打包
执行electron-builder进行打包,windows下会生成安装包exe和latest.yml等文件,执行exe安装软件;Mac下会生成安装包dmg、zip和latest-mac.yml文件,执行dmg安装软件。
注意:mac上不签名也可以打包成功,但是涉及到自动更新等需要身份认证的功能则不能用,也不能发布到mac app store中。所以说经过代码签名的MAC包才是完整的包。我们这里一定是经过代码签名的完整包!切记!
具体打包流程请参考:Electron 桌面应用打包(npm run build)简述(windows + mac)
MAC打包中报Error: Could not get code signature for running application错误可参考:Electron 打包Mac安装包代码签名问题解决方案
windows打包生成文件:
TIM%E6%88%AA%E5%9B%BE20180117165614.png

Mac打包生成文件:
TIM%E6%88%AA%E5%9B%BE20180117165401.png

6.软件升级版本,修改package.json中的version属性,例如:改为 version: “1.1.0” (之前为1.0.0);
7.再次执行electron-builder打包,Windows下将新版本latest.yml文件和exe文件(MAC下将latest-mac.yml,zip和dmg文件)放到package.json中build -> publish中的url对应的地址下;
8.在应用中触发更新检查,electron-updater自动会通过对应url下的yml文件检查更新;

windows上自动更新示例:

clipboard.png

clipboard.png

mac上自动更新示例:
clipboard.png

clipboard.png

附:项目目录层次:
图片描述

如果这篇文章对你的工作或者学习有帮助的话,请收藏或点个赞。如果对其中有什么不明白的或者报错,可以留言或者加QQ群140455228交流

注意:请支持原创,本文谢绝转载,确有需要可链接到本文。本文链接地址:https://segmentfault.com/a/11...

查看原文

逗比欢乐多 回答了问题 · 2017-12-25

解决json web token过期后怎么搞

JWT 过期时间尽可能的设置短,我这边是 1 分钟左右,随着 JWT Token 一起发送的还有
Refresh_token,Refresh_token 我是这么设计的 MD5(randomString),然后以 Refresh_token 为 key,有效期为value存入数据库或者 Redis 之类的,设计一个中间件,检查 JWT Token 时间,JWT Token过期的话,检查 Refresh_token 是否过期,Refresh_token 没有过期的生成新的 JWT Token 和 Refresh_token 返回给客户端,这样既解决了 JWT Token 时间过长 重放攻击问题,又避免了频繁登录问题。关键是 Refresh_token图片描述

关注 32 回答 10

逗比欢乐多 赞了回答 · 2017-12-23

解决json web token过期后怎么搞

这个并不是答案,放在这里而不是评论区是为了更多的人看到,不要踩我?

@lsxiao 你提出这个并发问题我才意识到jwt的这个缺陷,不过读到https://segmentfault.com/q/10... 这里@我只想帮妈妈洗碗 的回答我突然想到:
如果不是持续刷新token,而是过期前3分钟刷新token,刷新token把旧的token放入黑名单。后续校验一个token是不是在黑名单的时候放宽1分钟(就算在黑名单,但是距离放入黑名单的时间小于1分钟认为有效)就可以解决新token发放后旧token的请求失败的问题。

所以jwt的方案还是要有数据库存储黑名单的,不然没办法解决注销问题(但如果有数据库的存在,跨服务器的校验又是一个问题,如果再弄个认证服务器,感觉更复杂了)。现在还是非常困扰怎么更合理的解决jwt的续签和注销的问题。没有看到比较完善的文档。望大神们指教?

更新:

最近又对这个问题思考了一下,意识到并发问题其实是自寻烦恼,并发的起源是黑名单,加入黑名单的原因是要续签,所以最根本的问题是续签问题。那么续签的方式其实跟cookie是两个方式:

  1. cookie是每次访问对旧的sid进行延期,这个延期实际上是个定值。
  2. token的更新是个区间值,比如在网页端,如果cookie的有效期是30min,那么对一个token设置30min有效期和30min续签期。用户第二次访问如果在30min(非续签有效期)内不续签,第三次访问超过30min就退出了登录;如果第二次访问在30min~1h(续签有效期),那么进行续签,第三次访问超过1h就退出了登录。所以用户的登录有效期就是30min~1h。

那么黑名单其实是为了解决另外一个问题——注销,如果需要强制退出用户登录,那么后端就需要有个黑名单,每次解码前/后要进行数据库读取是否是黑名单。这个对于单类型客户端(同类型客户端登录互斥需求)是有必要存在的,总体来讲如果加解密开销影响较小的话,读黑名单的成本要比维护session低的多(量少)。

至于@faceair 的说法,是后续读到一篇文章(讲真,别再使用JWT了)(不过作者的观点说又重新发明了session,可是为什么session就不能重新发明呢?)才理解什么意思,他其实说的是一次性授权,这个过程理论上是连续的,而且有时间限制,还有就是授权只生效一次(比如跳到第三方进行支付),所以不存在续签问题,那么这个时间究竟是多久应该参照业务。当然他的说法还有点类似oauth2的应用。

这个问题之前写过一篇稿子的思考:
关于jwt的思考
但是还不完善,后续如果有进一步深入会再更新一下博文,写的不好,请轻踩。

关注 32 回答 10

逗比欢乐多 回答了问题 · 2017-12-15

gorm无法连接mysql?账号密码都对了

func ConnectionDb(){
    db, err := gorm.Open("mysql", "root:123456@(127.0.0.1:3306)/dbname?charset=utf8&parseTime=True&loc=Local")

    if err != nil {
        fmt.Println(err)
        panic("--- 数据库连接失败")
    }
    defer db.Close()
}

应该这样,注意格式

关注 3 回答 3

逗比欢乐多 赞了文章 · 2017-05-08

[PHP] 又是知乎,用 Beanbun 爬取知乎用户

最近看了很多关于爬虫入门的文章,发现其中大部分都是以知乎为爬取对象,所以这次我也以知乎为目标来进行爬取的演示,用到的爬虫框架为 PHP 编写的 Beanbun。

这次写的内容为爬取知乎的用户,下面就是详细说一下写爬虫的过程了。

爬取知乎用户的思路比较简单,就是从某个用户开始,先抓取这个用户关注的人和关注他的人,抓取到这些人后,再抓取他们的相关的用户。
现在知乎是可以使用游客身份进行浏览的,也省去了注册和登录这一部分。先随便找个大V吧,因为他们的关注者比较多,我选择的是大名鼎鼎的张公子,张公子的关注者有13万,就是说只爬取他的关注者,我们都能有13万的用户数据~

图片描述

在用户页面中打开chrome浏览器的开发者选项,点击关注者后就可以看到请求地址和数据。

clipboard.png

就以这个作为入口开始爬取了~
此处跳过框架的安装和队列的开启,直接上爬虫的代码:
(如果需要跳过的部分,可以看一下文档

<?php
use Beanbun\Beanbun;
use Beanbun\Lib\Db;
use GuzzleHttp\Client;

require_once(__DIR__ . '/vendor/autoload.php');

$beanbun = new Beanbun;
$beanbun->name = 'zhihu_user';
$beanbun->count = 5;
$beanbun->interval = 4;
$beanbun->seed = 'https://www.zhihu.com/api/v4/members/zhang-jia-wei/followers?include=data%5B*%5D.answer_count%2Carticles_count%2Cgender%2Cfollower_count%2Cis_followed%2Cis_following%2Cbadge%5B%3F(type%3Dbest_answerer)%5D.topics&offset=0&limit=20';
$beanbun->logFile = __DIR__ . '/zhihu_user_access.log';

上面是对爬虫的配置,开启5个进程同时爬取,设置爬取间隔为4秒。在爬去前,我们还要设置一下请求的headers,好让网站认为是人类再浏览他- -。headers的内容从开发者选项中一股脑粘贴进来。

clipboard.png

$beanbun->beforeDownloadPage = function ($beanbun) {
    // 在爬取前设置请求的 headers 
    $beanbun->options['headers'] = [
        'Host' => 'www.zhihu.com',
        'Connection' => 'keep-alive',
        'Cache-Control' => 'max-age=0',
        'Upgrade-Insecure-Requests' => '1',
        'User-Agent' => 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36',
        'Accept' => 'application/json, text/plain, */*',
        'Accept-Encoding' => 'gzip, deflate, sdch, br',
        'authorization' => 'oauth c3cef7c66a1843f8b3a9e6a1e3160e20',
    ];
};

而在请求到数据后,我还需要把他们存到数据库中,因为主要是演示,所以只保存用户的id,name,follower,following这四个数据。

// 数据库配置
Db::$config['zhihu'] = [
    'server' => '127.0.0.1',
    'port' => '3306',
    'username' => 'xxxx',
    'password' => 'xxxx',
    'database_name' => 'zhihu',
    'charset' => 'utf8',
];

$beanbun->afterDownloadPage = function ($beanbun) {
    // 获取的数据为 json,先解析
    $data = json_decode($beanbun->page, true);

    // 如果没有数据或报错,那可能是被屏蔽了。就把地址才重新加回队列
    if (isset($data['error']) || !isset($data['data'])) {        
        $beanbun->queue()->add($beanbun->url);
        $beanbun->error();
    }
    
    // 如果本次爬取的不是最后一页,就把下一页加入队列
    if ($data['paging']['is_end'] == false) {
        $beanbun->queue()->add($data['paging']['next']);
    }

    $insert = [];
    $date = date('Y-m-d H:i:s');

    foreach ($data['data'] as $user) {
        // 如果关注者或者关注的人小于5个,就不保存了
        if ($user['follower_count'] < 5 || $user['following_count'] < 5) {
            continue ;
        }
        $insert[] = [
            'id' => $user['id'],
            'name' => $user['name'],
            'follower' => $user['follower_count'],
            'following' => $user['following_count'],
            'created_at' => $date,
        ];
        // 把用户的关注者和关注的人列表加入队列
        $beanbun->queue()->add('https://www.zhihu.com/api/v4/members/' . $user['url_token'] . '/followers?include=data%5B*%5D.following_count%2Cfollower_count&limit=20&offset=0');
        $beanbun->queue()->add('https://www.zhihu.com/api/v4/members/' . $user['url_token'] . '/followees?include=data%5B*%5D.following_count%2Cfollower_count&limit=20&offset=0');
        }
    }

    if (count($insert)) {
        Db::instance('zhihu')->insert('zhihu_user', $insert);
    }
    // 把刚刚爬取的地址标记为已经爬取
    $beanbun->queue()->queued($beanbun->queue);
};
// 不需要框架来发现新的网址,
$beanbun->discoverUrl = function () {};
$beanbun->start();

接下来在命令行运行爬虫

$ php zhihu_user.php start

再去看一眼数据库,源源不断的用户数据保存进来了~
在一切顺利的情况下,我又稍微作了一下死,把爬取的间隔减到了2秒,于是在10几分钟之后,我被知乎封掉了....
这种情况比较常见的解决方式就是使用代理,下面就在原有爬虫基础上,增加一个简单的可定时更新的代理池。
先停止爬虫

$ php zhihu_user.php stop

网上有很多免费代理的网站,我随便选了一个提供免费代理的网站,爬取到代理的数据后,先请求一下163,如果成功的话就加入代理池。

function getProxies($beanbun) {
    $client = new \GuzzleHttp\Client();
    $beanbun->proxies = [];
    $pattern = '/<tr><td>(.+)<\/td><td>(\d+)<\/td>(.+)(HTTP|HTTPS)<\/td><td><div class=\"delay (fast_color|mid_color)(.+)<\/tr>/isU';
    
    for ($i = 1; $i < 5; $i++) {
        $res = $client->get("http://www.mimiip.com/gngao/$i");
        $html = str_replace(['  ', "\r", "\n"], '', $res->getBody());
        preg_match_all($pattern, $html, $match);
        foreach ($match[1] as $k => $v) {
            $proxy = strtolower($match[4][$k]) . "://{$v}:{$match[2][$k]}";
            echo "get proxy $proxy ";
            try {
                $res = $client->get('http://mail.163.com', [
                    'proxy' => $proxy,
                    'timeout' => 6
                ]);
                echo "success.\n";
            } catch (\Exception $e) {
                echo "error.\n";
            }
        }
    }
}

if ($argv[1] == 'start') {
    getProxies($beanbun);
}

$beanbun->startWorker = function($beanbun) {
    // 每隔半小时,更新一下代理池
    Beanbun::timer(1800, 'getProxies', $beanbun);
};

再在之前的 beforeDownloadPage 中加入

if (isset($beanbun->proxies) && count($beanbun->proxies)) {
    $beanbun->options['proxy'] = $beanbun->proxies[array_rand($beanbun->proxies)];
}

再次启动爬虫,爬虫还会接着之前的队列继续爬取。

$ php zhihu_user.php start

再看看数据库,使用代理可能会比之前慢一些,不过数据又继续增加了。
最终的代码可以在 Github 上查看

例子中的代理池还是比较简陋的,只是用来说明框架的灵活,而爬取到数据在这里就不做图表进行分析了,希望大家关注的也是写爬虫的过程。
最后如果你对这篇文章感兴趣,希望能到 Github 上给个 star 啦,谢谢~

查看原文

赞 5 收藏 17 评论 1

逗比欢乐多 赞了文章 · 2016-10-25

MySQL性能优化

MySQL性能优化可从如下几个方面着手

  • SQL优化
  • 索引优化
  • 数据库(表)结构优化
  • 系统配置优化
  • 服务器硬件优化

SQL优化

  • 开启慢查询记录日志,查找症状(很多时候都是一些慢查询拖累了整个数据库的性能)

    • 在配置文件中配置(my.cnf),配置完毕需要重启,不适合线上数据库
    #path可修改为绝对或者相对路径
    log-slow-queries=slow-log-path 
    #l查询时间超过2s记录
    long_query_time=2 
    #没有使用索引的查询记录
    log-queries-not-using-indexes
    
    • mysql命令行下配置
    sql#查看log_query_time变量的值
    show variables like "%long%";
    #如果long_query_time的值不是期望值,重新设定
    set global long_query_time=2;
    #查询 slow_query_log 和 slow_query_log_file的值
    show variables like "%slow%";
    #开启慢查询日志 on或者ON都可以,不区分大小写
    set global slow_query_log='on';
    #慢查询日志文件路径可修改
    set global slow_query_log='/data/mysql/slow.log'
    

    慢查询日志分析工具有官方的mysqldumpslow 和pt-query-digest,后者更加精确详细

  • explain 分析sql的执行

    • table 查询的数据表
    • type (可能的值 const, eq_reg, ref, range, index,all)
      主键或者唯一索引一般是const,性能最好
      eq_reg 是一种范围查找,唯一索引,主键可能是此种查找
      ref常见于连接查询,一个表基于另外一个索引的查找
      range 基于索引的范围查找
      index通常是对index的扫描
      All 是表扫描
    • possible_keys 查询中可以使用的索引
    • key 查询中实际使用到的索引,为null表示没有使用索引
    • key_len 索引长度,越小越好
    • ref 显示索引的那一列被使用了,最好是一个常数
    • rows 扫描的行数
    • extra
      出现using filesort 查询需要优化(group by),出现using temporary需要优化(order by 时容易出现)
  • 掌握一些sql的优化方法
    max, count,子查询,group by,limit

索引优化

  • 选择合适的列建立索引(在where中经常出现的查询条件的列应当创建索引,group by ,order by,on)

    • 索引字段越小越好
    • 离散度大的列放在联合索引的前面(离散度越大,过滤的数据越多)
      判断列的离散度可以根据select count(distinct col1), count(distinct col2) from table
  • 索引优化SQL的方法
    增加索引会影响写入效率(insert,update,delete)
    删除重复和冗余的索引
    使用工具pt-duplicate-key-checker分析
    使用pt-index-usage 工具配合慢查询日志来分析不再使用的索引(注意主从库的时候无法使用此工具精确判断)

数据库(表)结构优化

  • 选择合适的(列)数据类型

    • 选择可以存下数据的最小的数据类型
    • 选择尽量简单的数据类型
    • 尽可能对列加上not null(Innodb特性),给出default
    • 尽快能不使用text等大的数据类型,如果要用,尽量和其他字段分离,单独成表
  • 表的范式和反范式
  • 表的垂直拆分
    把原来有很多列的表拆分成多个表,降低表的宽度
    拆分原则:不经常使用的字段放在一个表,很大的字段放在一个表,常用的字段放在一个表
  • 表的水平拆分
    水平拆分解决单表数据量过大的问题,水平拆分之后的每一张表结构相同
    常用拆分方法:取模,hash等
    分表带来的挑战:跨分区表数据查询;统计及后台操作。使用汇总表,前后台业务分开

系统配置的优化

  • 修改/etc/sysctl.conf,优化系统网络参数
  • 修改/etc/security/limits.conf 优化打开文件数量
  • 硬件防火墙代替软件防火墙防止网络性能消耗
  • mysql配置文件

    • innodb_buffer_pool_size
    • innodb_buffer_pool_instances
      mysql 5.5引入,默认一个
    • ... 参数不在一一列举
  • 第三方工具优化mysql配置
    http://tools.percona.com/wizard

硬件优化

  • cpu选择
    核数不能超过32,mysql对多核的支持并不是特别优秀
  • 磁盘IO(RAID,常用RAID1+RAID0)
查看原文

赞 28 收藏 134 评论 7

逗比欢乐多 回答了问题 · 2016-08-20

解决为什么那么多人用Java开发B/S应用,而不用PHP?

这种月经智障问题,又来

关注 14 回答 14

逗比欢乐多 赞了回答 · 2016-08-20

为什么中国没有自己的编程语言?

有呀,王垠自己不就开发了一个Yin语言么?我还看到过一个脚本语言Ming(明).
只不过很多搞IT的国人都有一种鄙视自己人的心态,人家搞出来了,不是想着怎么借鉴学习,而是先想着怎么否定别人.

其实关键还在于就算你搞出来了,也不一定有人用.
Dart算是Google官方搞的编程语言,现在也是半死不活.
倒是Google的几个贝尔实验室出身的UNIX C开发者不爽C++和Java搞了个Golang倒是有些人用.
我不说其他语言,就说我熟悉的PHP.
对于鸟哥这种PHP核心开发者,他要是想搞出一门类似PHP的脚本语言,我觉得是完全有可能的.
但是编译过留意过PHP源代码的人都应该知道,Zend引擎只是项目中的一小部分(9.2MB),那些功能函数ext(108MB)才是大头,另外还有一些把PHP应用在Web上的sapi(cli/cgi/mod_php/fpm)也有3.1MB.所以说,就算你一个人搞出来了一个语言核心,但你不可能一个人搞出那么多库函数,所以说,有实力还不如参加到成熟的项目中去.所以,鸟哥才成为了PHP的核心开发者,PHP7性能的大幅提升,鸟哥功不可没.还有就是峰哥,为PHP开发了异步高性能网络编程扩展Swoole,相当于PHP界里的Node替代.所以说,没必要非得自己搞出一门编程语言才如何如何,给一门并不漂亮但广泛使用的语言(比如PHP)添砖加瓦,同样令人钦佩.
另外就是Facebook里的HPHPc的项目发起者赵海平,初期把PHP代码转为C++代码后编译运行,这个难度和工作量也是相当大的,不亚于开发一门语言,后面也正是因为Facebook对高性能的刚性需求(那时还没有PHP7),所以才出钱出力组织开发团队继续开发,直到发展到现在基本兼容PHP的HHVM(仅支持Linux平台).所以说,一个人的力量是非常有限的,没有大公司因为自身需求出钱出力是很难成功的.

关注 11 回答 11

认证与成就

  • 获得 10 次点赞
  • 获得 8 枚徽章 获得 0 枚金徽章, 获得 1 枚银徽章, 获得 7 枚铜徽章

擅长技能
编辑

(゚∀゚ )
暂时没有

开源项目 & 著作
编辑

(゚∀゚ )
暂时没有

注册于 2014-05-11
个人主页被 745 人浏览