{ yeah : 必须哒 } No place to place should record our youth?

10Feb/110

【转】设置自动重连的ssh代理通道

Posted by alacner

我目前常用的翻墙办法就是拿ssh搭个代理通道,然后chrome + switch!插件一起配合,这就算翻墙了。这法子只要拿个机器跑一小脚本,比如:

ssh -D 7070 -qnN [username]@[server]

但是ssh通道如果闲置了一段时间,就会自动断连,等我需要用到代理的时候往往又得蛋疼的重新跑一遍,非常麻烦。所以我刻苦学习前辈的经验,找到一个解决办法,在mac或linux下都可使用,分享如下:

  • 把ssh配置为免密码登录,这个一搜一大把,略过不提
  • 在/etc/inittab的最后一行加上:

    tunl:345:respawn:/usr/bin/ssh -D 7070 -qnN [username]@[server] > /dev/null 2>&1

  • 让修改的inittab马上生效

    sudo init q

然后这个ssh通道就会自动重连了。

【转自:Volcano】

Filed under: 技术日志 No Comments
10Feb/110

[转]PHP数组交集的优化

Posted by alacner

假设我们正在运营一个手机相关的网站,用户可以通过指定若干参数(如操作系统,屏幕分辨率,摄像头像素等等)来筛选自己想要的手机。不过由于手机的 参数多,且不同的手机其参数差异大,所以参数表结构通常是纵表(一个参数是一行),而不是横表(一个参数是一列),此时使用若干参数来取结果,通常就是把 每个单独参数来取结果,再一起取交集。

假定每个参数会包含一千个左右的产品ID(int),以此为前提来模拟生成一些数据:

<?php
$rand = function() {
 $result = array();
 for ($i = 0; $i < 1000; $i++) {
 $result[] = mt_rand(1, 10000);
 }
 return $result;
};
$param_a = $rand();
$param_b = $rand();
?>

注意:如果测试数据集过小的话,结论可能会出现不一致。

先看看通过PHP内置方法array_intersect实现的性能:

<?php
$time = microtime(true);
$result = array_intersect($param_a, $param_b);
$time = microtime(true) - $time;
echo "array_intersect: {$time}n";
?>


在优化之前,我们先来看看array_intersect一些特殊的地方:

</pre>
<span style="font-family: 宋体; font-size: 12pt;"><?php</span>

<span style="font-family: 宋体; font-size: 12pt;">$param_a = array(1, 2, 2);</span>

<span style="font-family: 宋体; font-size: 12pt;">$param_b = array(1, 2, 3);</span>

<span style="font-family: 宋体; font-size: 12pt;">var_dump(</span>

<span style="font-family: 宋体; font-size: 12pt;"> array_intersect($param_a, $param_b),</span>

<span style="font-family: 宋体; font-size: 12pt;"> array_intersect($param_b, $param_a)</span>

<span style="font-family: 宋体; font-size: 12pt;">);</span>

<span style="font-family: 宋体; font-size: 12pt;">?></span>

<span style="font-family: 宋体; font-size: 12pt;">

  • array_intersect($param_a, $param_b): 1, 2, 2

  • array_intersect($param_b, $param_a): 1, 2

也就是说,如果在第一个数组参数中有重复元素的话,则array_intersect会返回所有满足条件的重复元素。改写array_intersect的时候最好兼容这些功能。

下面看看通过自定义方法int_array_intersect实现的性能:

<?php

function int_array_intersect()

{

if (func_num_args() < 2) {

trigger_error('param error', E_USER_ERROR);

}

$args = func_get_args();

foreach ($args AS $arg) {

if (!is_array($arg)) {

trigger_error('param error', E_USER_ERROR);

}

}

$intersect = function($a, $b) {

$result = array();

$length_a = count($a);

$length_b = count($b);

for ($i = 0, $j = 0; $i < $length_a && $j < $length_b; null) {

if($a[$i] < $b[$j] && ++$i) {

continue;

}

if($a[$i] > $b[$j] && ++$j) {

continue;

}

$result[] = $a[$i];

if (isset($a[$next = $i + 1]) && $a[$next] != $a[$i]) {

++$j;

}

++$i;

}

return $result;

};

$result = array_shift($args);

sort($result);

foreach ($args as $arg) {

sort($arg);

$result = $intersect($result, $arg);

}

return $result;

}

$time = microtime(true);

$result = int_array_intersect($param_a, $param_b);

$time = microtime(true) - $time;

echo "int_array_intersect: {$time}n";

?>

直觉上,我们肯定会认为内置函数快于自定义函数,但本例中结果恰恰相反:

  • array_intersect: 0.023918151855469

  • int_array_intersect: 0.0026049613952637

为什么?原因在于int_array_intersect操作的都是整数,而array_intersect操作的都是字符串,即便你传给它整数,也会当做字符串处理。

注:测试结果基于PHP5.3.5,不同版本结论可能存在差异

参考:Faster array_intersect

【转自:http://huoding.com/2011/01/30/43】

I've written a set-intersection implementation which is MUCH (5+ times) faster than array_intersect()

PHP Code:

function intersect($s1,$s2) {

$i=0;

$j=0;

$N count($s1);

$M count($s2);

$intersection = array();

while($i<$N && $j<$M) {

if($s1[$i]<$s2[$j]) $i++;

else if($s1[$i]>$s2[$j]) $j++;

else {

$intersection[] = $s1[$i];

$i++;

$j++;

}

}

return $intersection;

}

Both arrays must be pre-sorted, but I did the performance comparison including this time, just to be fair .

Just thought I'd share this one.

I should probably have been clearer about the differences. In my case I had suitable arrays, and need the speed more than the generality. Its is definately significantly faster for my data at any rate.

Perhaps I'll take a look at the array_intersect source at some point.

Thanks for the comments guys

Filed under: 技术日志 No Comments
27Jan/110

[转]Git和Repo扫盲——如何取得Android源代码

Posted by alacner

Git 是 Linux Torvalds 为了帮助管理 Linux 内核开发而开发的一个开放源码的分布式版本控制软件,它不同于SubversionCVS这样的集中式版本控制系统。在集中式版本控制系统中只有一个仓库(repository),许多个工作目录(working copy),而像Git这样的分布式版本控制系统中(其他主要的分布式版本控制系统还有BitKeeper、MercurialGNU ArchBazaarDarcsSVKMonotone等),每一个工作目录都包含一个完整仓库,它们可以支持离线工作,本地提交可以稍后提交到服务器上。分布式系统理论上也比集中式的单服务器系统更健壮,单服务器系统一旦服务器出现问题整个系统就不能运行了,分布式系统通常不会因为一两个节点而受到影响

因为Android是由kernel、Dalvik、Bionic、prebuilt、build等多个Git项目组成,所以Android项目编写了一个名为Repo的Python的脚本来统一管理这些项目的仓库,使得Git的使用更加简单。

这几天William为了拿Android最新的sourcecode,学习了一下git和repo的一些基本操作,整理了一个如何取得Android代码的How-To,今天把他贴上来。

1、Git的安装

在Ubuntu 8.04上安装git只要设定了正确的更新源,然后使用apt-get就可以了,有什么依赖问题,就让它自己解决吧。其中cURL是一个利用URL语法在命令行下工作的文件传输工具,会在后面安装Repo的时候用到。

sudo apt-get install git-core curl

2、安装Repo

首先确保在当前用户的主目录下创建一个/bin目录(如果没有的话),然后把它(~/bin)加到PATH环境变量中

接下来通过cURL来下载Repo脚本,保存到~/bin/repo文件中

curl http://android.git.kernel.org/repo >~/bin/repo

别忘了给repo可执行权限

chmod a+x ~/bin/repo

3、初始化版本库

如果是想把Android当前主线上最新版本的所有的sourcecode拿下来,我们需要repo的帮助。

先建立一个目录,比如~/android,进去以后用repo init命令即可。

repo init -u git://android.git.kernel.org/platform/manifest.git

这个过程会持续很长的时间(至少可以好好睡一觉),具体要多少时间就取决于网络条件了

最后会看到 repo initialized in /android这样的提示,就说明本地的版本库已经初始化完毕,并且包含了当前最新的sourcecode

如果想拿某个branch而不是主线上的代码,我们需要用-b参数制定branch名字,比如:

repo init -u git://android.git.kernel.org/platform/manifest.git -b cupcake

另一种情况是,我们只需要某一个project的代码,比如kernel/common,就不需要repo了,直接用Git即可。

git clone git://android.git.kernel.org/kernel/common.git

这也需要不少的时间,因为它会把整个Linux Kernel的代码复制下来。

如果需要某个branch的代码,用git checkout即可。比如我们刚刚拿了kernel/common.get的代码,那就先进入到common目录,然后用下面的命令:

git checkout origin/android-goldfish-2.6.27 -b goldfish

这样我们就在本地建立了一个名为goldfish的android-goldfish-2.6.27分支,代码则已经与android-goldgish-2.6.27同步。我们可以通过git branch来列出本地的所有分支。

4、同步版本库

使用epo sync命令,我们把整个Android代码树做同步到本地,同样,我们可以用类似

repo sync project1 project2 …

这样的命令来同步某几个项目

如果是同步Android中的单个项目,只要在项目目录下执行简单的

git pull

即可。

5、通过GitWeb下载代码

另外,如果只是需要主线上某个项目的代码,也可以通过GitWeb下载,在shortlog利用关键字来搜索特定的版本,或者找几个比较新的tag来下载还是很容易的。

Git最初是为Linux内核开发而设计,所以对其他平台的支持并不好,尤其是Windows平台,必须要有Cygwin才可以。现在,得益于msysgit项目,我们已经可以不需要Cygwin而使用Git了。另外,Git Extensions是一个非常好用的Windows Shell扩展,它能与资源管理器紧密集成,甚至提供了Visual Studio插件。它的官方网站上有一分不错的说明文档,感兴趣的朋友可以看一看。

至于Git的参考文档,我推荐Git Magic,这里还有一个Git Magic的中文版

 
 

源文档 <http://www.williamhua.com/2009/04/29/git-and-repo-for-dummies/>

Filed under: 技术日志 No Comments
27Jan/110

[转]git svn实战

Posted by alacner

我之前写了几个wordpress插件,比如inline-javascript, code-prettify。这些插件都托管在wordpress.org提供的svn服务器上,但是我实在太喜欢在git下活动了,因此动了点心思,想把插件代码传到github上,开发完之后利用git-svn传到wordpress的svn服务上。

 

照着这个思路,捋起袖子就开干了。

用git-svn抓取插件代码

 

wordpress的插件svn库大且缓慢,如果直接用git-svn去clone代码,一定会慢死,所以我按照以前的笔记,用git从大型svn快速clone代码。

 

以code-prettify插件为例,首先需要读取这个插件创建时的版本号

 

svn log http://svn.wp-plugins.org/code-prettify|tail -4|head -1

 

得到了如下信息,获得一个版本号 318479

 

r318479 | plugin-master | 2010-12-03 20:12:29 +0800 (五, 03 12 2010) | 1 line

 

开始clone代码

 

git svn clone -s --prefix=svn/ -r318479:HEAD http://svn.wp-plugins.org/code-prettify

 

设置git仓库

 

首先把代码传了一份到github: https://github.com/volca/code-prettify

 

然后操作本地git仓库

 

git branch -m svn

git remote add origin git@github.com:volca/code-prettify.git

git checkout master

 

本地svn分支对应svn的远程仓库,本地master分支对应github的远程仓库

Happy time

 

现在可以按照平常的习惯在git下更改代码,然后用git push到github上。

 

如果需要更新代码到svn上,按这个流程操作就可以了:

 

git checkout svn

git merge master

git svn dcommit

 

如果需要发布wordpress插件的新版本,这个在svn里就是一个打tag的过程,用git-svn操作非常简单,下面的例子表示发布code-prettify插件的0.3版本:

 

git svn tag 0.3

 

[转自:http://www.ooso.net/archives/576]

Filed under: 技术日志 No Comments
27Jan/110

用git从svn里clone最后几个版本

Posted by alacner

一般情况下git svn clone这个操作会从第一个版本开始同步,如果版本号已经到了好几万(或更高?),这个操作会相当的费时。

当时还想着能不能hack一下git-svn脚本,其实后来看看文档,clone操作可以使用参数-r$REVNUMBER:HEAD检出指定版本后的代码,因此,更好的步骤应该是这样:

  • svn info http://your-svn, 并记录最后的版本号,假设是260
  • 假设要检出最后10个版本,做个简单的减法: 260 – 10 = 250
  • 开始clone操作了

    git svn clone -r250:HEAD --prefix=svn/ http://your-svn

按这个办法,clone的时间的确是减少了许多。

Filed under: 技术日志 No Comments
27Jan/110

[转]基于PECL OAuth打造微博应用

Posted by alacner

最近,国内主要门户网站相继开放了微博平台,对开发者而言这无疑是个利好消息,不过在实际使用中却发现平台质量良莠不齐,有很多不完善的地方,就拿PHP版SDK来说吧,多半都是用TwitterOAuth改的,一旦多平台集成,很容易出现命名冲突之类的问题。

既然官方SDK不给力,那我们只能发扬自力更生的革命精神了!好消息是PHP本身已经有了一个标准的OAuth实现:PECL OAuth!下面以此为例来讲解一下如何实现微博应用:

说明:首先需要对OAuth概念有一定的了解,如不清楚可以参考我以前写的文章:OAuth那些事儿,其次需要注册成为各个微博平台(新浪腾讯搜狐网易)的开发者,拿到属于你自己的CONSUMER_KEY和CONSUMER_SECRET(有时也被称作APP_*)。

下面开始!假定我们要开发一个类似Follow5微博通的应用,简单点说就是把消息同时发送到多个微博平台,出于安全性的考虑,不会使用HTTP Basic,而会使用OAuth,这就需要我们先拿到Access Token和Access Token Secret。

以新浪微博为例,大致的代码如下:

<?php

 

session_start();

 

$request_token_url = 'http://api.t.sina.com.cn/oauth/request_token';

$authorize_url = 'http://api.t.sina.com.cn/oauth/authorize';

$access_token_url = 'http://api.t.sina.com.cn/oauth/access_token';

 

$oauth = new OAuth(

'YOUR_CONSUMER_KEY',

'YOUR_CONSUMER_SECRET',

OAUTH_SIG_METHOD_HMACSHA1,

OAUTH_AUTH_TYPE_FORM

);

 

if (empty($_GET['oauth_verifier'])) {

$callback_url = "http://{$_SERVER['HTTP_HOST']}{$_SERVER['REQUEST_URI']}";

 

$request_token = $oauth->getRequestToken($request_token_url);

 

$_SESSION['oauth_token_secret'] = $request_token['oauth_token_secret'];

 

$param = array(

'oauth_token' => $request_token['oauth_token'],

'oauth_callback' => $callback_url

);

 

header("Location: {$authorize_url}?" . http_build_query($param));

exit;

}

 

$oauth->setToken($_GET['oauth_token'], $_SESSION['oauth_token_secret']);

 

$access_token = $oauth->getAccessToken(

$access_token_url, null, $_GET['oauth_verifier']

);

 

var_dump($access_token);

 

?>

腾讯微博相比较而言有点特殊,大致代码如下:

<?php

 

session_start();

 

$request_token_url = 'https://open.t.qq.com/cgi-bin/request_token';

$authorize_url = 'https://open.t.qq.com/cgi-bin/authorize';

$access_token_url = 'https://open.t.qq.com/cgi-bin/access_token';

 

$oauth = new OAuth(

'YOUR_CONSUMER_KEY',

'YOUR_CONSUMER_SECRET',

OAUTH_SIG_METHOD_HMACSHA1,

OAUTH_AUTH_TYPE_FORM

);

 

$oauth->setNonce(md5(mt_rand()));

 

if (empty($_GET['oauth_verifier'])) {

$callback_url = "http://{$_SERVER['HTTP_HOST']}{$_SERVER['REQUEST_URI']}";

 

$request_token = $oauth->getRequestToken($request_token_url, $callback_url);

 

$_SESSION['oauth_token_secret'] = $request_token['oauth_token_secret'];

 

$param = array(

'oauth_token' => $request_token['oauth_token']

);

 

header("Location: {$authorize_url}?" . http_build_query($param));

exit;

}

 

$oauth->setToken($_GET['oauth_token'], $_SESSION['oauth_token_secret']);

 

$access_token = $oauth->getAccessToken(

$access_token_url, null, $_GET['oauth_verifier']

);

 

var_dump($access_token);

 

?>

注意:参数nonce和callback的设置,详见:使用 PECL 的 OAuth 库访问 QQ 微博 API

照猫画虎就能得到搜狐和网易的Access Token和Access Token Secret了,我就不罗嗦了。

下面继续做我们的微博应用,发消息一般都是文本形式的,不过有中国特色的微博开放平台支持文本加图片的方式:图片上传到服务器,但本身并不参与签名。这和标准OAuth是冲突的,所以要扩展一下PECL OAuth,并且尽可能兼容原类的使用方法和习惯:

<?php

 

class MicroblogOAuth extends OAuth

{

public $consumer_key;

 

public $signature_method;

 

public $auth_type;

 

public $nonce;

 

public $timestamp;

 

public $token;

 

public $version;

 

public $request_engine;

 

public $last_response;

 

public function setAuthType($auth_type)

{

if (parent::setAuthType($auth_type)) {

$this->auth_type = $auth_type;

 

return true;

}

 

return false;

}

 

public function setNonce($nonce)

{

if (parent::setNonce($nonce)) {

$this->nonce = $nonce;

 

return true;

}

 

return false;

}

 

public function setTimestamp($timestamp)

{

if (parent::setTimestamp($timestamp)) {

$this->timestamp = $timestamp;

 

return true;

}

 

return false;

}

 

public function setToken($token, $token_secret)

{

if (parent::setToken($token, $token_secret)) {

$this->token = $token;

 

return true;

}

 

return false;

}

 

public function setVersion($version)

{

if (parent::setVersion($version)) {

$this->version = $version;

 

return true;

}

 

return false;

}

 

public function setRequestEngine($request_engine)

{

try {

parent::setRequestEngine($request_engine);

 

$this->request_engine = $request_engine;

} catch(OAuthException $e) {

echo $e->getMessage();

}

}

 

public function getLastResponse()

{

return parent::getLastResponse() ?: $this->last_response;

}

 

public function upload($url, $file, $param = array(), $header = array())

{

$boundary = sprintf('%010d', mt_rand());

 

$header[] = "Content-Type: multipart/form-data; boundary={$boundary}";

 

$oauth = array(

'oauth_consumer_key' => $this->consumer_key,

'oauth_nonce' => $this->nonce,

'oauth_signature_method' => $this->signature_method,

'oauth_timestamp' => $this->timestamp,

'oauth_token' => $this->token,

'oauth_version' => $this->version,

);

 

if ($this->auth_type == OAUTH_AUTH_TYPE_FORM) {

$param += $oauth;

 

$param['oauth_signature'] = $this->generateSignature(

OAUTH_HTTP_METHOD_POST, $url, $param

);

} else {

$oauth_header = array();

 

$oauth['oauth_signature'] = $this->generateSignature(

OAUTH_HTTP_METHOD_POST, $url, $param

);

 

foreach ($oauth AS $name => $value) {

$oauth_header[] = $name . '="' . $value . '"';

}

 

$header[] = 'Authorization: OAuth ' . implode(', ', $oauth_header);

}

 

$content_disposition = function($name, $filename = null) {

$result = 'Content-Disposition: form-data; name="' . $name . '"';

 

if ($filename !== null) {

$result .= '; filename="' . $filename . '"';

}

 

return $result;

};

 

$content = array();

 

foreach ($file as $name => $value) {

$filename = pathinfo($value, PATHINFO_BASENAME);

 

switch(strtolower(pathinfo($filename, PATHINFO_EXTENSION))) {

case 'gif';

$mime = 'image/gif';

break;

case 'jpeg':

case 'jpg':

$mime = 'image/jpg';

break;

case 'png';

$mime = 'image/png';

break;

default:

$mime = 'application/octet-stream';

}

 

$content_type = "Content-Type: {$mime}";

 

$content[] = "--{$boundary}";

$content[] = $content_disposition($name, $filename);

$content[] = $content_type;

$content[] = '';

 

$content[] = file_get_contents($value);

}

 

ksort($param);

 

foreach ($param as $name => $value) {

$content[] = "--{$boundary}";

$content[] = $content_disposition($name);

$content[] = '';

 

$content[] = $value;

}

 

$content[] = "--{$boundary}--";

$content[] = '';

 

$content = implode("\r\n", $content);

 

if ($this->request_engine == OAUTH_REQENGINE_CURL) {

$header[] = 'Expect:';

 

$curl = curl_init();

 

curl_setopt($curl, CURLOPT_POST, true);

curl_setopt($curl, CURLOPT_POSTFIELDS, $content);

curl_setopt($curl, CURLOPT_HTTPHEADER, $header);

curl_setopt($curl, CURLOPT_URL, $url);

 

curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);

 

$response = curl_exec($curl);

 

curl_close($curl);

} else {

$header[] = 'Connection: close';

 

$context = stream_context_create(array(

'http' => array(

'protocol_version' => '1.1',

'method' => 'POST',

'content' => $content,

'header' => implode("\r\n", $header),

)

));

 

$response = file_get_contents($url, false, $context);

}

 

if ($response) {

$this->last_response = $response;

 

return true;

}

 

return false;

}

}

 

?>

注意:为了让代码潮一点,用了一些PHP5.3以上版本才有的特性,你可以改写成低版本。

如果使用CURL方式发送请求的话,最好发送一个空的Expect头,否则如果POST数据大于1K,CURL会自作主张发送 Expect:100-continue头,对多数Web服务器来说这没问题,但低版本Lighttpd(如1.4)则会出现HTTP 417错误。

详见:'Expect' header gives HTTP error 417

如果使用PHP Streams方式发送请求的话,缺省使用的是HTTP1.0版本,可以通过tcpdump命令来检测这种现象,大致方法如下:

shell> tcpdump -A host foo.com

此时,某些防火墙会过滤掉非标准HTTP1.0的请求头,如Host请求头,从而造成错误。

详见:由于 HTTP request 不规范导致的被防火墙拦截

新类MicroblogOAuth直接扩展自PECL的OAuth类!随着PHP内核API的逐渐类化,这样的扩展方式将会越来越常见,值得开发人员重视。

为了让调用方式更统一,使用工厂方法包装MicroblogOAuth的实例化过程:

<?php

 

function OAuth($consumer_key, $consumer_secret, $signature_method, $auth_type)

{

$instance = new MicroblogOAuth(

$consumer_key,

$consumer_secret,

$signature_method,

$auth_type

);

 

$instance->consumer_key = $consumer_key;

$instance->signature_method = $signature_method;

 

$instance->setAuthType($auth_type);

$instance->setNonce(md5(mt_rand()));

$instance->setTimestamp(time());

$instance->setVersion('1.0');

 

if (extension_loaded('curl')) {

$instance->setRequestEngine(OAUTH_REQENGINE_CURL);

} else {

$instance->setRequestEngine(OAUTH_REQENGINE_STREAMS);

}

 

$instance->last_response = null;

 

return $instance;

}

 

?>

先看看搜狐是如何发送文本加图片消息的:

<?php

 

$text = 'hello, world.';

$image = 'http://www.foo.com/bar.gif';

 

$oauth = OAuth(

'YOUR_CONSUMER_KEY',

'YOUR_CONSUMER_SECRET',

OAUTH_SIG_METHOD_HMACSHA1,

OAUTH_AUTH_TYPE_AUTHORIZATION

);

 

$oauth->setToken(

'YOUR_ACCESS_TOKEN',

'YOUR_ACCESS_TOKEN_SECRET'

);

 

$oauth->upload(

'http://api.t.sohu.com/statuses/upload.json',

array('pic' => $image),

array('status' => oauth_urlencode($text))

);

 

$result = json_decode($oauth->getLastResponse(), true);

 

var_dump($result);

 

?>

说明:搜狐要求文本要先编码,然后和图片一起发送,这点不同于其它微博开放平台。

再看看网易是如何发送文本加图片消息的:

<?php

 

$text = 'hello, world.';

$image = 'http://www.foo.com/bar.gif';

 

$oauth = OAuth(

'YOUR_CONSUMER_KEY',

'YOUR_CONSUMER_SECRET',

OAUTH_SIG_METHOD_HMACSHA1,

OAUTH_AUTH_TYPE_AUTHORIZATION

);

 

$oauth->setToken(

'YOUR_ACCESS_TOKEN',

'YOUR_ACCESS_TOKEN_SECRET'

);

 

$oauth->upload(

'http://api.t.163.com/statuses/upload.json',

array('pic' => $image)

);

 

$result = json_decode($oauth->getLastResponse(), true);

 

if (isset($result['upload_image_url'])) {

$text .= " {$result['upload_image_url']}";

}

 

$oauth->fetch(

'http://api.t.163.com/statuses/update.json',

array('status' => $text),

OAUTH_HTTP_METHOD_POST

);

 

$result = json_decode($oauth->getLastResponse(), true);

 

var_dump($result);

 

?>

说明:网易发送文本加图片消息是分两步实现的,先上传图片,然后把图片的URL附加在文本信息的后面再发送到服务器,这点不同于其它微博开放平台。

收工!微博开放平台的使用并没有太多复杂的地方,仔细看文档调试,一般的问题都很容易解决。有了上面的基础代码,只要再使用适配器模式分别包装一下各个微博平台,很容易就能实现一套通用SDK,搞定新浪,腾讯,搜狐,网易!

【转自:http://huoding.com/2011/01/16/42】

Filed under: 技术日志 No Comments
24Jan/110

Linux VPS一键安装包集合

Posted by ofeng

无名博客再次收集更新了一些Linux VPS下的一键安装包,一键安装包可以大大简化人工成本,节约时间,不仅方便了使用Linux VPS的小白,对于Linux老手来讲编译安装需要输入大量的命令,如果是配置生产环境需要耗费大量的时间。这些一键安装包使用非常简单,傻瓜化的安装方 式,采用Shell编写,容易修改。这次添加了cnBeta网友留言里的一键安装包。

Web套装一键安装包
LNMP一键安装包
LNMP一键安装包是一个用Linux Shell编写的可以为CentOS/RadHat、Debian/Ubuntu VPS(VDS)或独立主机安装LNMP(Nginx、MySQL、PHP、phpMyAdmin)生产环境的Shell程序。
适用系统:CentOS/Debian/Ubuntu
安装方法:猛击这里

LNAMP一键安装包
LNAMP 是指由 Linux(CentOS),Nginx,Apache,Mysql,Php 为主,其他诸如Pure-ftpd,Jailkit为辅的一套生产环境安装包.所有操作均集成在一个Linux Shell脚本文件中,管理员可方便的进行安装,卸载,增设用户虚拟主机(子域),删除用户虚拟主机(子域)等操作.最大限度方便系统管理员,同时不会影 响后续其他软件的安装兼容(有限)。
适用系统:Linux CentOS 5 (32bit/64bit)
安装方法:猛击这里

LLsMP一键安装包
LLsMP 是 Linux + Litespeed + MySQL + PHP 的一鍵安裝包
适用系统:CentOS/Debian
安装方法:猛击这里

CentOS LAMP/LNMP一键安装包
此一键安装脚本包含两个安装选项分别是:
lamp (apache + mysql + php + zend + eAccelerator + vsftpd + phpmyadmin)
lnmp (nginx + mysql + php + zend + eAccelerator + vsftpd + phpmyadmin)
适用系统:CentOS 5
安装方法:猛击这里

PPTP VPN一键安装包
PPTP是最常用的VPN软件
适用系统:CentOS 5 32bit/64bit
OpenVZ VPS要启用TUN/TAP
安装方法:猛击这里

CentOS OpenVPN一键安装包
OpenVPN是更安全的开源VPN软件
适用系统:CentOS
安装方法:猛击这里

CentOS L2TP VPN一键安装包
OpenVPN是更安全的开源VPN软件
适用系统:CentOS 32Bit(适用于XEN VPS)
安装方法:猛击这里
控制面板一键安装包
Kloxo一键安装包
Kloxo是一个优秀的Web控制面板,有商业版本和免费版本。免费版本的Kloxo允许绑定40个域名,对普通客户来讲40个域名也足够用了。
适用系统:CentOS 5
安装方法:猛击这里

Virtualmin/Webmin一键安装包
Virtual/Webmin是在使用上非常好上手的一款Linux主机面板,最重要的的是它是免费的,买不起cPanel、DirectAdmin的朋友可以试一试哦,绝对让你有惊喜。
适用系统:CentOS 5 32Bit/64Bit
安装方法:猛击这里

ISPConfig一键安装包
ISPConfig 是Linux的一款开源的虚拟主机管理程序,带Web控制面板,可通过Web控制面板管理虚拟主机、开设网站、开设邮箱、开设和管理mysql数据库、支 持DNS解析和监控服务器运行状况,IPTable防火墙 Shell 服务管理等功能。支持中文。
适用系统:CentOS 5
安装方法:猛击这里

http://www.cnbeta.com/articles/133147.htm

21Jan/110

【转】php加速 PHP APC 浅析

Posted by alacner

PHP APC提供两种缓存功能,即缓存Opcode(目标文件),我们称之为apc_compiler_cache。同时它还提供一些接口用于PHP开发人员将用户数据驻留在内存中,我们称之为apc_user_cache。我们这里主要控讨php-apc的配置。

安装PHP APC

作为测试环境,我们这里使用的是CentOS5.3(2.6.18-128.el5PAE) + Apache2.0(prefork) + php5.2。我们可以去pecl apc下载APC-3.0.19.tgz

[cc lang='bash']
# tar -xzvf APC-3.0.19.tgz
#cd APC-3.0.19
# /usr/bin/phpize
# ./configure --enable-apc --enable-mmap --enable-apc-spinlocks --disable-apc-pthreadmutex
#make
#make install
[/cc]
注意:我们这里支持mmap,同时采用spinlocks自旋锁。Spinlocks是Facebook推荐使用,同时也是APC开发者推荐使用的锁机制。

PHP APC 配置参数

如果你使用的系统环境跟我的测试环境是一样的话,可以在/etc/php.d目录下创建文件apc.ini,并且相关配置写入/etc/php.d/apc.ini文件。这里,我们挑了一些常用到的配置,并进行探讨。把相关的配置放在一起解释。

apc.enabled=1
apc.enabled默认值是1,你可设成0禁用APC。如果你设置为0的时候,同样把extension=apc.so也注释掉(这样可以节约内存资源)。一旦启用了APC功能,则会缓存Opcodes到共享内存。

APC既然把数据缓存在内存里面,我们就有必要对它进行内存资源限定。通过这二个配置可以限定APC可以使用的内存空间大小。apc.shm_segments指定了使用共享内存块数,而apc.shm_size则指定了一块共享内存空间大小,单位是M。所以,允许APC使用的内存大小应该是 apc.shm_segments * apc.shm_size = 30M。你可以调整一块共享内存的大小空间。当然,一块共享内存最大值是受操作系统限制的,即不能超过/proc/sys/kernel/shmmax大小。否则APC创建共享内存的时候,会失败。在apc.shm_size达到了上限的时候,你可以通过设置apc.shm_segments来允许APC使用更多的内存空间。我们推荐,如果调用APC使用内存空间的话,先考滤apc.shm_size,后考滤apc.shm_segments。具体数值,可以根据apc.php监控情况进行规划与调整。值得注意的是,每一次调整需要重启httpd守护进程,这样可以重新加载apc.so模块。跟随着httpd守护进程启动,apc.so模块就会加载。apc.so加载初始化的时候,通过mmap请求分配内存指定大小的内存,即apc.shm_size * apc.shm_segments。而且,这里使用的是匿名内存映射方式,通过映射一个特殊设备/dev/zero,提供一个"大型"的,填满了零的内存供APC管理。
为了验证以上陈述,我们注释掉apc.ini配置,并且写了以下php脚本观察apc.so模块初始化的分配的内存空间。

[cc lang='php']
//@file: apc_load.php
if (!extension_loaded('apc')) {
dl('apc.so'); #加载apc.so模块
echo posix_getpid(); #//输出当前进程的pid,我这里这里输出的是14735
ob_flush();
flush();
sleep(3600); #让进程进入休眠状态.这样,我们可以观察内存分配情况
}
?>
[/cc]
[cc lang='bash']
#strace -p `cat /var/run/httpd.pid`
open("/var/www/html/apc_load.php", O_RDONLY) = 13
...
mmap2(NULL, 31457280, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0) = 0xb5ce7000
...
nanosleep({3600, 0},
[/cc]

红色部分,我们可以看出。通过mmap系统内核调用分配了30M(31457280/1024/1024)内存空间。PROT_READ|PROT_WRITE表示该内存空间可供读取与写入。MAP_SHARED表示该内存空间与其它进程是共享的,即其它进程也可以进行读取与写入,我们可以通过apc.php进行管理该块内存空间亦是受益于此设定。MAP_ANONYMOUS则表示匿名映射。其中fd=-1表示忽略,因为这里映射的特殊设备/dev/zero。最后的0表示无偏移量。我们还可以通过进程映像文件查看该块内存的具体情况
[cc lang='bash']
#cat /proc/14735/smaps

b5ce7000-b7ae7000 rw-s 00000000 00:08 633695 /dev/zero (deleted)
Size: 30720 kB
Rss: 44 kB
Shared_Clean: 0 kB
Shared_Dirty: 0 kB
Private_Clean: 0 kB
Private_Dirty: 44 kB
[/cc]
可以很容易地发现起始地址0xb5ce7000与上面mmap系统内核调用返回的地址一样。该块内存是可读写rw,并与其它进程共享s。而/dev/zero则是映射文件,该文件节点是633695。其中,size表示进程可以使用的内存空间,而rss则表示实际分配的内存空间,且由Private_Dirty可以看出,实际分配的44kb内存是由当前进程自己分配的。

apc.num_files_hint = 1000
apc.user_entries_hint = 4096

这二配置指定apc可以有多少个缓存条目。apc.num_files_hint说明你估计可能会有多少个文件相应的opcodes需要被缓成,即大约可以有多少个apc_compiler_cache条目。另外apc.user_entries_hint则说明你估计可能会有多少个apc_userdata_cache条目需要被缓存。如果项目中不使用apc_store()缓存用户数据的话,该值可以设定得更小。也就是说apc.num_files_hint与apc.user_entries_hint之和决定了APC允许最大缓存对象条目的数量。准确地设置这二个值可以得到最佳查询性能。当然,如果你不清楚要进行多少缓存(缓存对象实例)的情况下,你可以不必修改这二项配置。
其中apc.user_entries_hint要根据项目实际开发使用了apc_store()条目估计其值大小。相较而言,apc.num_files_hint可以通过find命令,更容易地估计其大小。比如我们的web根目是/var/vhosts,则使用下面的find命令可以大致地统计当前apc.num_files_hint数目.

[cc lang='bash']
#find /var/vhosts \( -name “*.php” -or -name “*.inc” \) -type f -print |wc -l
1442
[/cc]

apc.stat = 1
apc.stat_ctime = 0

这二个参数,只跟apc_compiler_cache缓存相关,并不影响apc_user_cache。我们前面提到过apc_complier_cache,它缓存的对象是php源文件一一对应的opcodes(目标文件)。PHP源文件存放在磁盘设备上,与之相对应的Opcodes目标文件位置内存空间(共享内存),那么当php源文件被修改以后,怎么通知更新内存空间的opcodes呢?每次接收到请求后,APC都会去检查打开的php源文件的最后修改时间,如果文件的最后修改时间与相应的内存空间缓存对象记录的最后修改时间不一致的话,APC则会认为存放在内存空间的Opcode目标文件(缓存对象)已经过期了,acp会将缓存对象清除并且保存新解析得到的Opcode。我们关心的是,即便没有更新任何php源文件,每次接受到http请求后,APC都会请求系统内核调用stat()来获取php源文件最后修改时。我们可以通过将apc.stat设置为0,要求APC不去检查Opcodes相对应的php源文件是否更新了。这样可以获得最佳的性能,我们也推荐这么做。不过,这样做有一点不好的就是,一旦有PHP源文件更新了之后,需要重启httpd守护进程或者调用apc_cache_clear()函数清空APC缓存来保证php源文件与缓存在内存空间的Opcodes相一致。

[cc lang='php']
define('ROOTP', dirname(__FILE__) . '/');
include(ROOTP . 'i1.php');
require(ROOTP . 'i2.php');
include_once(ROOTP . 'i3.php');
require_once(ROOTP . 'i4.php');
require(ROOTP . 'i5.php');
include(ROOTP . 'i6.php');
?>
[/cc]
[cc lang='bash']
# strace -e trace=file -p `cat /var/run/httpd.pid`
getcwd("/var/www/html", 4096) = 14
stat64("/var/www/html/i1.php", {st_mode=S_IFREG|0644, st_size=39, ...}) = 0
stat64("/var/www/html/i2.php", {st_mode=S_IFREG|0644, st_size=39, ...}) = 0
lstat64("/var", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
lstat64("/var/www", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
lstat64("/var/www/html", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
lstat64("/var/www/html/i3.php", {st_mode=S_IFREG|0644, st_size=39, ...}) = 0
open("/var/www/html/i3.php", O_RDONLY) = 12
stat64("/var/www/html/i3.php", {st_mode=S_IFREG|0644, st_size=39, ...}) = 0
lstat64("/var", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
lstat64("/var/www", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
lstat64("/var/www/html", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
lstat64("/var/www/html/i4.php", {st_mode=S_IFREG|0644, st_size=39, ...}) = 0
open("/var/www/html/i4.php", O_RDONLY) = 12
stat64("/var/www/html/i4.php", {st_mode=S_IFREG|0644, st_size=39, ...}) = 0
stat64("/var/www/html/i5.php", {st_mode=S_IFREG|0644, st_size=39, ...}) = 0
stat64("/var/www/html/i6.php", {st_mode=S_IFREG|0644, st_size=39, ...}) = 0
chdir("/tmp") = 0

# strace -e trace=file -p `cat /var/run/httpd.pid`
getcwd("/var/www/html", 4096) = 14
open("/var/www/html/i3.php", O_RDONLY) = 12
open("/var/www/html/i4.php", O_RDONLY) = 12
chdir("/tmp") = 0
[/cc]
对比可见,当apc.stat=0时,省了很多系统内核调用,我们没有看到系统内核调用stat64了。其中,i3.php和i4.php分别是php的include_once和require_once函数调用,它要交给fstat()系统内核调用来检查文件是否打开过。单从性能角度出发的话,require比require_once性能更佳。

设置apc.stat_ctime的意义并是很大。如果apc.stat_ctime值为1时,仅当php源文件的创建时间(ctime)大于php源文件的最后修改时间(mtime)时,缓存对象的mtime时间会被php源文件的ctime所代替,否则缓存对象的mtime依然记录为php源文件的mtime。这样做是防止通过cvs, svn或者rsync等工具刷新php源文件的mtime,这样会导致APC通过比对php源文件的创建时间ctime来决定缓存对象有没有过期。我们推荐该保持默认值,即apc.stat_ctime = 0

apc.ttl=0
apc.user_ttl=0

缓存对象的生命周期。其中ttl表示Time To Live,意味着指定时间后缓存对象会被清除。其中0表示永不过期。我们前面提过,APC能缓存的条目是受限定的,如果你把ttl设置永不过期的话,当缓存条目已满或者缓存空间不够,之后的缓存都将失败。
其中apc.ttl作用于apc_compiler_cache。当apc.ttl大于0时,每次请求都会对比这次的请求时间与上一次请求时间之差是不是大于apc.ttl,如果大于apc.ttl,则会被认缓存条目过期了,会被清理。
比较有意思的是apc.user_ttl,它主要作用于apc_user_cache缓存。我们知道,这种类型的缓存是通过apc_store($key, $var, $ttl = 0)创建的缓存对象。函数apc_store()中指定的$ttl与php.ini中设定的apc.user_ttl有什么异同,是我们比较关心的。因为它们同样作用于apc_userdata_cache缓存。经过分析,我们知道:判断apc_user_cache缓存过期的依据是,当apc.user_ttl大于0,且这次http请求时间与上一次http请求时间之差大于apc.user_ttl,则认为相应的缓存条目已过期;或者,user.data.ttl(php函数apc_store()中指定的$ttl)大于0,且这次http请求时间与缓存对象创建时间ctime之差大于user.data.ttl,则同样认为缓存条目已过期,会被清除。
我们推荐,如果你的项目较为稳定,并且apc.stat设置为0。同时apc.shm_size、apc.num_files_hint设置合理的话,apc.ttl建议设置为0。即apc_compiler_cache永不回收,直到重启httpd守护进程或者调用函数apc_cache_clear()清缓存。至于apc.user_ttl,建议设置为0,由开发人员调用apc_store()函数的时候,设置$ttl来指定该缓存对象的生命周期。

apc.slam_defense=0
apc.write_lock=1
apc.file_update_protection=2

之所以把这三个配置放在一起解释,是因为他们的意义很相近。其中apc.file_update_protection最好理解,它的单位是时间单位秒。如果当前http请求时间与php源文件最好修改时间mtime之差小于apc.file_update_protection时间,APC则不会缓存该php源文件与之对应的Opcodes,直到接下来的某次访问,并且访问时间与php源文件的最后修改时间大于apc.file_update_protection时间,相之相应的Opcodes才会被缓存到共享内存空间。这样做的好处是,不容易被用户访问到你正在修改的源文件。我们推荐在开发环境,该值可以设置得更大一点,但在运营环境,我们推荐保留默认值即可。
当你的网站并发量很大的时候,可能出现由http守护进程fork的多个子进程同时缓存同一份Opcodes的情况。通过apc.slam_defense则可以减少这种事情的发生机率。比如,apc.slam_defense值设置为60的时候,当遇到未缓存的Opcodes,每100次有60次是不缓存的。对于并发量不大的网站,我们推荐该值设定为0,对于并发量高的网站我们可以根据统计适当地调整该值。而apc.write_lock是一个布尔值,当该值设置为1的时候,当多个进程同时缓存同一份Opcodes时,仅当最先那个进程缓存有效,其它的无效。通过apc.write_lock设置,有效地避免了缓存写竞争的出现。

apc.max_file_size=1M
apc.filters = NULL
apc.cache_by_default=1

这三个配置放在一起,是因为他们都用于限制缓存。其中apc.max_file_size表示如果php源文件超过了1M,则与之对应的opcodes不被缓存。而apc.filters指定一个文件过滤列表,以逗号(,)隔开。当apc.cache_by_default等于1时,与apc.filters列表中指定的文件名相匹配的文件不会被缓存。相反,apc.cache_by_default等于0时,仅缓存与acp.filters列表中指定的文件相匹配的文件。

总结

1,使用Spinlocks锁机制,能够达到最佳性能。
2,APC提供了apc.php,用于监控与管理APC缓存。不要忘记修改管理员名和密码
3,APC默认通过mmap匿名映射创建共享内存,缓存对象都存放在这块"大型"的内存空间。由APC自行管理该共享内存
4,我们需要通过统计调整apc.shm_size、apc.num_files_hints、apc.user_entries_hint的值。直到最佳
5,好吧,我承认apc.stat = 0 可以获得更佳的性能。要我做什么都可以接受.
6,PHP预定义常量,可以使用apc_define_constants()函数。不过据APC开发者介绍说pecl hidef性能更佳,抛异define吧,它是低效的。
7,函数apc_store(),对于系统设置等PHP变量,生命周期是整个应用(从httpd守护进程直到httpd守护进程关闭),使用APC比Memcached会更好。必竟不要经过网络传输协议tcp。
8,APC不适于通过函数apc_store()缓存频繁变更的用户数据,会出现一些奇异现象。

【转自:http://www.perfgeeks.com/?p=298】

Tagged as: , , No Comments
20Jan/110

[转]memcached分布式hash策略测试

Posted by alacner

版权声明:原创作品,允许转载,转载时请务必以超链接形式标明文章原始出版、作者信息和本声明。否则将追究法律责任。http://blog.csdn.net/mayongzhan - 马永占,myz,mayongzhan

配合memcache监控程序,测试memcache分布式,文章参考了网上某位牛人的文章。

测试crc32 fnv standard consistent 组合情况下的item分布情况及添加新服务器对现有item命中率的影响。

先开memcached服务器

#!/bin/bash
##############################
# MyZ 2009-07-12
# File:memcached_12.sh
##############################
port=11212
for (( i=11212; i<11224; i++ ))
do
/usr/local/bin/memcached -u root -p $i -m 10 &
done

./memcached.sh

结论
使用memcache这种客户端下的方法保证分配均匀的基础下,存货率做高的是crc32+ consistent。

测试结果

//crc32 standard
192.168.1.101:11212 => items:9812
192.168.1.101:11213 => items:10153
192.168.1.101:11214 => items:9895
192.168.1.101:11215 => items:9985
192.168.1.101:11216 => items:10206
192.168.1.101:11217 => items:9958
192.168.1.101:11218 => items:10159
192.168.1.101:11219 => items:9941
192.168.1.101:11220 => items:9924
192.168.1.101:11221 => items:9967
192.168.1.101:11222 => items:0%
192.168.1.101:11223 => items:0%

//fnv standard
192.168.1.101:11212 => items:9911
192.168.1.101:11213 => items:9978
192.168.1.101:11214 => items:9928
192.168.1.101:11215 => items:10053
192.168.1.101:11216 => items:9952
192.168.1.101:11217 => items:10055
192.168.1.101:11218 => items:10013
192.168.1.101:11219 => items:10089
192.168.1.101:11220 => items:9947
192.168.1.101:11221 => items:10074
192.168.1.101:11222 => items:0
192.168.1.101:11223 => items:0

//crc32 consistent
192.168.1.101:11212 => items:12466
192.168.1.101:11213 => items:10175
192.168.1.101:11214 => items:8436
192.168.1.101:11215 => items:9118
192.168.1.101:11216 => items:11757
192.168.1.101:11217 => items:9208
192.168.1.101:11218 => items:10343
192.168.1.101:11219 => items:8417
192.168.1.101:11220 => items:8716
192.168.1.101:11221 => items:11364
192.168.1.101:11222 => items:0
192.168.1.101:11223 => items:0

//fnv consistent
192.168.1.101:11212 => items:9014
192.168.1.101:11213 => items:13178
192.168.1.101:11214 => items:10053
192.168.1.101:11215 => items:4302
192.168.1.101:11216 => items:10875
192.168.1.101:11217 => items:4906
192.168.1.101:11218 => items:15593
192.168.1.101:11219 => items:9993
192.168.1.101:11220 => items:8093
192.168.1.101:11221 => items:13993
192.168.1.101:11222 => items:0
192.168.1.101:11223 => items:0

用于检测memcache的程序配置部分

for ($i = 11212; $i < 11222; $i++) {
$MEMCACHE_SERVERS[] = '192.168.1.101:'.$i; // add more as an array
}
$MEMCACHE_SERVERS[] = '192.168.1.101:11222'; // add more as an array
$MEMCACHE_SERVERS[] = '192.168.1.101:11223'; // add more as an array

测试代码

[cc lang='php']
/**
* @name test.php
* @date Thu Jul 12 21:18:59 CST 2009
* @copyright 马永占(MyZ)
* @author 马永占(MyZ)
* @link http://blog.csdn.net/mayongzhan/
*/
set_time_limit(0);

//crc32 standard
//ini_set('memcache.hash_function','crc32');
//ini_set('memcache.hash_strategy','standard');
//crc32 consistent
ini_set('memcache.hash_function','crc32');
ini_set('memcache.hash_strategy','consistent');
//fnv standard
//ini_set('memcache.hash_function','fnv');
//ini_set('memcache.hash_strategy','standard');
//fnv consistent
//ini_set('memcache.hash_function','fnv');
//ini_set('memcache.hash_strategy','consistent');

$memcache_server_ip = '192.168.1.101';
for ($i = 11212; $i < 11222; $i++) {
$memcache_servers_ports[] = $i;
}
$memcache_servers_ports_add[] = 11222;
$memcache_servers_ports_add[] = 11223;

$mem = new Memcache;
//add servers
foreach ($memcache_servers_ports as $value) {
$mem->addServer($memcache_server_ip, $value);
}
//set items
for($i = 0; $i < 100000; $i++) {
$mem->set($i, $i, 0, 3600);
}
//add 2 new servers
foreach ($memcache_servers_ports_add as $value) {
$mem->addServer($memcache_server_ip, $value);
}
//get items
for($i = 0; $i < 100000; $i++) {
$mem->get($i);
}
$status = $mem->getExtendedStats();
foreach ($status as $key=>$value) {
echo $key
. ' => items:'
. $value['curr_items']
. '
';
}
$mem->close();
?>

[/cc]

19Jan/110

A Brief History of Pi

Posted by alacner

Pi is a name given to the ratio of the circumference of a circle to the diameter. That means, for any circle, you can divide the circumference (the distance around the circle) by the diameter and always get exactly the same number. It doesn't matter how big or small the circle is, Pi remains the same. Pi is often written using the symbol and is pronounced "pie", just like the dessert.

A Brief History of Pi
Ancient civilizations knew that there was a fixed ratio of circumference to diameter that was approximately equal to three. The Greeks refined the process and Archimedes is credited with the first theoretical calculation of Pi.

In 1761 Lambert proved that Pi was irrational, that is, that it can't be written as a ratio of integer numbers.

In 1882 Lindeman proved that Pi was transcendental, that is, that Pi is not the root of any algebraic equation with rational coefficients. This discovery proved that you can't "square a circle", which was a problem that occupied many mathematicians up to that time. (More information on squaring the circle.)

How many digits are there? Does it ever end?
Because Pi is known to be an irrational number it means that the digits never end or repeat in any known way. But calculating the digits of Pi has proven to be an fascination for mathematicians throughout history. Some spent their lives calculating the digits of Pi, but until computers, less than 1,000 digits had been calculated. In 1949, a computer calculated 2,000 digits and the race was on. Millions of digits have been calculated, with the record held (as of September 1999) by a supercomputer at the University of Tokyo that calculated 206,158,430,000 digits.

(first 1,000 digits)

More about the History of Pi can be found at the Mac Tutor Math History archives.

Approximation of Pi
Archimedes calculated that Pi was between 3 10/71 and 3 1/7 (also written 223/71 < < 22/7 ). 22/7 is still a good approximation. 355/113 is a better one.

Pi Web Sites
Pi continues to be a fascination of many people around the world. If you are interested in learning more, there are many web sites devoted to the number Pi. There are sites that offer thousands, millions, or billions of digits, pi clubs, pi music, people who calculate digits, people who memorize digits, Pi experiments and more. Check this Yahoo page for a complete listing.

A Cool Pi Experiment
One of the most interesting ways to learn more about Pi is to do pi experiments yourself. Here is a famous one called Buffon's Needle.

In Buffon's Needle experiment you can drop a needle on a lined sheet of paper. If you keep track of how many times the needle lands on a line, it turns out to be directly related to the value of Pi.

Buffon's Needle Simulation Applet (Michael J. Hurben)
Buffon's Needle (George Reese, Office for Mathematics, Science and Technology Education University of Illinois Champaign-Urbana)

Digits of Pi

First 100 digits

3.1415926535 8979323846 2643383279 5028841971 6939937510 5820974944 5923078164 0628620899 8628034825 3421170679 ...

First 1000 digits
3.1415926535 8979323846 2643383279 5028841971 6939937510 5820974944 5923078164 0628620899 8628034825 3421170679 8214808651 3282306647 0938446095 5058223172 5359408128 4811174502 8410270193 8521105559 6446229489 5493038196 4428810975 6659334461 2847564823 3786783165 2712019091 4564856692 3460348610 4543266482 1339360726 0249141273 7245870066 0631558817 4881520920 9628292540 9171536436 7892590360 0113305305 4882046652 1384146951 9415116094 3305727036 5759591953 0921861173 8193261179 3105118548 0744623799 6274956735 1885752724 8912279381 8301194912 9833673362 4406566430 8602139494 6395224737 1907021798 6094370277 0539217176 2931767523 8467481846 7669405132 0005681271 4526356082 7785771342 7577896091 7363717872 1468440901 2249534301 4654958537 1050792279 6892589235 4201995611 2129021960 8640344181 5981362977 4771309960 5187072113 4999999837 2978049951 0597317328 1609631859 5024459455 3469083026 4252230825 3344685035 2619311881 7101000313 7838752886 5875332083 8142061717 7669147303 5982534904 2875546873 1159562863 8823537875 9375195778 1857780532 1712268066 1300192787 6611195909 2164201989

Formulas for Pi

Vieta's Formula

2/PI = 2/2 * ( 2 + 2 )/2 * (2 + ( ( 2 + 2) ) )/2 * ...c

Leibnitz's Formula

PI/4 = 1/1 - 1/3 + 1/5 - 1/7 + ...

Wallis Product

PI/2 = 2/1 * 2/3 * 4/3 * 4/5 * 6/5 * 6/7 * ...

2/PI = (1 - 1/22)(1 - 1/42)(1 - 1/62)...

Lord Brouncker's Formula

4/PI = 1 + 1

----------------

2 + 32

------------

2 + 52

---------

2 + 72 ...

(PI2)/8 = 1/12 + 1/32 + 1/52 + ...

(PI2)/24 = 1/22 + 1/42 + 1/62 + ...

Euler's Formula

(PI2)/6 = (n = 1..) 1/n2 = 1/12 + 1/22 + 1/32 + ...

(or more generally...)

(n = 1..) 1/n(2k) = (-1)(k-1) PI(2k) 2(2k) B(2k) / ( 2(2k)!)

B(k) = the k th Bernoulli number. eg. B0=1 B1=-1/2 B2=1/6 B4=-1/30 B6=1/42 B8=-1/30 B10=5/66. Further Bernoulli numbers are defined as (n 0)B0 + (n 1)B1 + (n 2)B2 + ... + (n (n-1))B(N-1) = 0 assuming all odd Bernoulli #'s > 1 are = 0. (n k) = binomial coefficient = n!/(k!(n-k)!)

See Power Summations #2 for simplified expressions (without the Bernoulli notation) of these sums for given values of k.

Tagged as: , No Comments