快速找出php中可能导致cpu飙升问题的代码行

 更新时间:2016年11月25日 16:19  点击:2168
cpu飙升占100%不但是与数据库或硬盘的io输入有关,但程序也是一个非常重要的地方了,今天小编找到一个代码可以测试你的php引起cpu占100%问题的解决办法,有兴趣的朋友可进入参考。

用cpu接近100%时,你如何找到导致cpu飙升的原因?我的思路是,首先找到进程正在执行的代码行,从而确定可能有问题的代码段。然后,再仔细分析有问题的代码段,从而找出原因。
如果你的程序使用的是c、c++编写,那么你可以很容易的找到正在执行的代码行。但是,程序是php编写的,如何找到可能有问题的代码行呢?这个问题就是本文要解决的问题。
背景知识:
大家都知道php是一个解释性语言。用户编写的php代码会生成opcode,由解释器引擎去解释执行。在解释执行过程中,有一个全局变量包含了执行过 程中用到的各种数据。它就是executor_globals。在源码的Zend/zend_globals.h 文件中可以找到他的类型定义。

 代码如下 复制代码

struct _zend_executor_globals {
    zval **return_value_ptr_ptr;

    zval uninitialized_zval;
    zval *uninitialized_zval_ptr;

    zval error_zval;
    zval *error_zval_ptr;

    zend_ptr_stack arg_types_stack;

    /* symbol table cache */
    HashTable *symtable_cache[SYMTABLE_CACHE_SIZE];
    HashTable **symtable_cache_limit;
    HashTable **symtable_cache_ptr;

    zend_op **opline_ptr;

    HashTable *active_symbol_table;
    HashTable symbol_table;     /* main symbol table */

    HashTable included_files;   /* files already included */

    JMP_BUF *bailout;

    int error_reporting;
    int orig_error_reporting;
    int exit_status;

    zend_op_array *active_op_array;

    HashTable *function_table;  /* function symbol table */
    HashTable *class_table;     /* class table */
    HashTable *zend_constants;  /* constants table */

    zend_class_entry *scope;
    zend_class_entry *called_scope; /* Scope of the calling class */

    zval *This;

    long precision;

    int ticks_count;

    zend_bool in_execution;
    HashTable *in_autoload;
    zend_function *autoload_func;
    zend_bool full_tables_cleanup;

    /* for extended information support */
    zend_bool no_extensions;

#ifdef ZEND_WIN32
    zend_bool timed_out;
    OSVERSIONINFOEX windows_version_info;
#endif

    HashTable regular_list;
    HashTable persistent_list;

    zend_vm_stack argument_stack;

    int user_error_handler_error_reporting;
    zval *user_error_handler;
    zval *user_exception_handler;
    zend_stack user_error_handlers_error_reporting;
    zend_ptr_stack user_error_handlers;
    zend_ptr_stack user_exception_handlers;

    zend_error_handling_t  error_handling;
    zend_class_entry      *exception_class;

    /* timeout support */
    int timeout_seconds;

    int lambda_count;

    HashTable *ini_directives;
    HashTable *modified_ini_directives;

    zend_objects_store objects_store;
    zval *exception, *prev_exception;
    zend_op *opline_before_exception;
    zend_op exception_op[3];

    struct _zend_execute_data *current_execute_data;

    struct _zend_module_entry *current_module;

    zend_property_info std_property_info;

    zend_bool active;

    void *saved_fpu_cw;

    void *reserved[ZEND_MAX_RESERVED_RESOURCES];
};

这里我们只说两个对我们比较重要的变量,active_op_array 和 current_execute_data。
active_op_array变量中保存了引擎正在执行的op_array(想了解什么是op_array请点击查看)。在Zend/zend_compile.h中有关于op_array的数据类型的定义。

 代码如下 复制代码

struct _zend_op_array {
    /* Common elements */
    zend_uchar type;
    char *function_name;
    zend_class_entry *scope;
    zend_uint fn_flags;
    union _zend_function *prototype;
    zend_uint num_args;
    zend_uint required_num_args;
    zend_arg_info *arg_info;
    zend_bool pass_rest_by_reference;
    unsigned char return_reference;
    /* END of common elements */

    zend_bool done_pass_two;

    zend_uint *refcount;

    zend_op *opcodes;
    zend_uint last, size;

    zend_compiled_variable *vars;
    int last_var, size_var;

    zend_uint T;

    zend_brk_cont_element *brk_cont_array;
    int last_brk_cont;
    int current_brk_cont;

    zend_try_catch_element *try_catch_array;
    int last_try_catch;

    /* static variables support */
    HashTable *static_variables;

    zend_op *start_op;
    int backpatch_count;

    zend_uint this_var;

    char *filename;
    zend_uint line_start;
    zend_uint line_end;
    char *doc_comment;
    zend_uint doc_comment_len;
    zend_uint early_binding; /* the linked list of delayed declarations */

    void *reserved[ZEND_MAX_RESERVED_RESOURCES];
};

看完定义,就不用我多说了把。定义中,filename和 function_name分别保存了正在执行的文件名和方法名。
current_execute_data保存了正在执行的op_array的execute_data。execute_data保存了每个op_array执行过程中的一些数据。其定义在,Zend/zend_compile.h:

 代码如下 复制代码
struct _zend_execute_data {
    struct _zend_op *opline;
    zend_function_state function_state;
    zend_function *fbc; /* Function Being Called */
    zend_class_entry *called_scope;
    zend_op_array *op_array;
    zval *object;
    union _temp_variable *Ts;
    zval ***CVs;
    HashTable *symbol_table;
    struct _zend_execute_data *prev_execute_data;
    zval *old_error_reporting;
    zend_bool nested;
    zval **original_return_value;
    zend_class_entry *current_scope;
    zend_class_entry *current_called_scope;
    zval *current_this;
    zval *current_object;
    struct _zend_op *call_opline;
};


定义中的opline就是正在执行的opcode。opcode的结构定义如下:

 代码如下 复制代码
struct _zend_op {
    opcode_handler_t handler;
    znode result;
    znode op1;
    znode op2;
    ulong extended_value;
    uint lineno;
    zend_uchar opcode;
};

其中lineno就是opcode所对应的行号。
示例说明:
看完上面的数据结构定义,你是否已经知道如何找php正在执行的文件名,方法名和行号呢?如果还有疑问的话,那就接着看下面的例子。创建一个文件test.php,代码如下:

 代码如下 复制代码
<?php
function test1(){
        while(true){
              sleep(1);
        }
}
test1();
?>

cli方式执行php脚本,加入执行的进程号为14973。我们使用gdb命令来调试进程。

 代码如下 复制代码
$sudo gdb -p 14973
(gdb) print (char *)executor_globals.active_op_array->filename
$1 = 0x9853a34 "/home/xinhailong/test/php/test.php"
(gdb) print (char *)executor_globals.active_op_array->function_name
$2 = 0x9854db8 "test1"
(gdb) print executor_globals->current_execute_data->opline->lineno
$3 = 4

很显然,他正在执行第四行的sleep方法。
如果上面的方法你感觉麻烦,那你可以使用.gdbinit文件。这个文件在php源码的根目录下。使用方法如下:

 代码如下 复制代码
$sudo gdb -p 14973
(gdb) source /home/xinhailong/.gdbinit
(gdb) zbacktrace
[0xa453f34] sleep(1) /home/xinhailong/test/php/test.php:4
[0xa453ed0] test1() /home/xinhailong/test/php/test.php:7
(gdb)

题外话:
从php5.6开始,php中集成了一个phpdbg的工具。可以像gdb调试c语言程序一样,调试php程序。感兴趣的话,可以打开下面的连接看看

下面来给各位介绍一段用php实现的Libevent HTTP客户端实现程序,有需要了解的朋友可与小编一起来学习一下。

php Libevent HTTP

 代码如下 复制代码

<?php
//请求完成回调
function _request_handler($req, $base) {
  global $pend_req;
  //echo __FUNCTION__, PHP_EOL;
 
  if (is_null($req)) {
    //echo "Timed out\n";
  } else {
    $response_code = $req->getResponseCode();
 
    if ($response_code == 0) {
      //echo "Connection refused\n";
    } elseif ($response_code != 200) {
      //echo "Unexpected response: $response_code\n";
    } else {
      //echo "Success: $response_code\n";
      /*
      $buf = $req->getInputBuffer();
      echo "Body:\n";
      while ($s = $buf->readLine(EventBuffer::EOL_ANY)) {
      echo $s, PHP_EOL;
      }
       */
    }
  }
  $pend_req--;
  //退出循环
  if (!$pend_req) {
    $base = $conn->getBase();
    $base->exit(NULL);
  }
  //释放内存
  unset($req);
  unset($conn);
}
 
//$address = "www.111cn.net";
$pend_req = 0;
$port = 80;
//初始化event base
$base = new EventBase();
echo "Event method used: ", $base->getMethod(), PHP_EOL;
 //使用异步DNS
$dns_base = new EventDnsBase($base, TRUE);
$f= fopen("./50000.txt","r");
while (!feof($f))
{
  $line = fgets($f);
  //echo $address;
  $address = trim($line);
  //新建http连接事件到base
  $conn = new EventHttpConnection($base, $dns_base, $address, $port);
  $conn->setTimeout(1);
  //设置请求回调
  $req = new EventHttpRequest("_request_handler", $conn);
 
  $req->addHeader("Host", $address, EventHttpRequest::OUTPUT_HEADER);
  $req->addHeader("Content-Length", "0", EventHttpRequest::OUTPUT_HEADER);
  $conn->makeRequest($req, EventHttpRequest::CMD_GET, "/");
  $pend_req++;
}
fclose($f);
//事件主循环
$base->loop();
?>

c语言版,

 代码如下 复制代码

#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <evhttp.h>
#include <event2/event.h>
#include <event2/http.h>
#include <event2/bufferevent.h>
typedef struct my_struct_s my_struct_t;
 
struct my_struct_s {
  struct evhttp_connection *conn;
  struct evhttp_request *req;
  struct evhttp_uri *uri;
  struct event *cleanup;
};
 
struct event_base *Base_Primary;
 
char *trimwhitespace(char *str)
{
  char *end;
 
  // Trim leading space
  while(isspace(*str)) str++;
 
  if(*str == 0)  // All spaces?
    return str;
 
  // Trim trailing space
  end = str + strlen(str) - 1;
  while(end > str && isspace(*end)) end--;
 
  // Write new null terminator
  *(end+1) = 0;
 
  return str;
}
 
void connection_free(int sock, short which, void *arg) {
  //printf("freeing connection!!! The socket's FD would have been closed when the HTTP request ended and the ->req object would have been free'd\n");
 
  // Get our structure object
  my_struct_t *myStruct = arg;
 
  // Cleanup our properties
  event_free(myStruct->cleanup);
  evhttp_connection_free(myStruct->conn);
  evhttp_request_free(myStruct->req);
  evhttp_uri_free(myStruct->uri);
 
  // Free our custom structure
  free(myStruct);
}
 
void http_request_done(struct evhttp_request *req, void *arg){
 
  // Get our custom struct
  my_struct_t *myStruct = arg;
 
  // Setup our timeout information (we delay 5 seconds)
  struct timeval Timeout;
  Timeout.tv_sec = 0;
  Timeout.tv_usec = 0;
 
  // Add this structure to our cleanup base to be cleaned up synchronously
  // TODO: Probably not the best way to cleanup and event, but it'l work for the purposes of illustration.
  // This way would ensure no race conditions exist, but it's probably not the most efficient depending on how many requests, etc we're dealing with.
  myStruct->cleanup = evtimer_new(Base_Primary, connection_free, (void *)myStruct);
  evtimer_add(myStruct->cleanup, &Timeout);
 
  //printf("http_request_done, we put our custom strucutre into a cleanup event to be freed!\n");
}
 
int http_req(char *uri) {
 
  // Allocate our custom struture
  my_struct_t *myStruct = malloc(sizeof(my_struct_t));
 
  // Create our EVHTP connection and request
  myStruct->uri = evhttp_uri_parse(uri);
  myStruct->conn = evhttp_connection_base_new(Base_Primary, NULL, uri, 80);
  myStruct->req = evhttp_request_new(http_request_done, myStruct);
  evhttp_add_header(evhttp_request_get_output_headers(myStruct->req), "Host", "localhost");
  evhttp_add_header(evhttp_request_get_output_headers(myStruct->req), "Connection", "close");
  evhttp_make_request(myStruct->conn, myStruct->req, EVHTTP_REQ_GET, uri);
  evhttp_connection_set_timeout(myStruct->req->evcon, 2);
  return 1;
}
 
 
// Define our primary function
int main(int argc, char *argv[]) {
 
  // Initialize our bases
  Base_Primary = event_base_new();
 
  char filename[] = "/tmp/50000.txt"; //文件名
  FILE *fp;
  char StrLine[1024];             //每行最大读取的字符数
  char *host;
  if((fp = fopen(filename,"r")) == NULL) //判断文件是否存在及可读
  {
    printf("error!");
    return -1;
  }
 
  while (!feof(fp))
  {
    fgets(StrLine,1024,fp);  //读取一行
    host = StrLine;
    host = trimwhitespace(host);
    //printf("%s", host); //输出
    http_req(host);
  }
  fclose(fp); 
 
  //
  //event_base_loop(Base_Primary);
  event_base_dispatch(Base_Primary);
 
  // Free our primary base
  event_base_free(Base_Primary);
  return 1;
}

微信公众平台实现微信网页登陆授权开发其实是非常的简单了,因为官方的参考程序了,下面小编就看了一站长根据官方参考做的一个网页登陆授权例子,大家可看看。

文件1:index.php

//换成自己的接口信息

$appid = 'XXXXX';

header('location:https://open.weixin.qq.com/connect/oauth2/authorize?appid='.$appid.'&redirect_uri=127.0.0.1/oauth.php&response_type=code&scope=snsapi_userinfo&state=123&connect_redirect=1#wechat_redirect');

参数说明:

参数
是否必须
说明
appid 公众号的唯一标识
redirect_uri 授权后重定向的回调链接地址,请使用urlencode对链接进行处理
response_type 返回类型,请填写code
scope 应用授权作用域,snsapi_base (不弹出授权页面,直接跳转,只能获取用户openid),snsapi_userinfo (弹出授权页面,可通过openid拿到昵称、性别、所在地。并且,即使在未关注的情况下,只要用户授权,也能获取其信息
state 重定向后会带上state参数,开发者可以填写a-zA-Z0-9的参数值
#wechat_redirect 无论直接打开还是做页面302重定向时候,必须带此参数


文件二:oauth.php

 代码如下 复制代码
<?php
$code = $_GET['code'];
$state = $_GET['state'];
//换成自己的接口信息
$appid = 'XXXXX';
$appsecret = 'XXXXX';
if (empty($code)) $this->error('授权失败');
$token_url = 'https://api.weixin.qq.com/sns/oauth2/access_token?appid='.$appid.'&secret='.$appsecret.'&code='.$code.'&grant_type=authorization_code';
$token = json_decode(file_get_contents($token_url));
if (isset($token->errcode)) {
    echo '<h1>错误:</h1>'.$token->errcode;
    echo '<br/><h2>错误信息:</h2>'.$token->errmsg;
    exit;
}
$access_token_url = 'https://api.weixin.qq.com/sns/oauth2/refresh_token?appid='.$appid.'&grant_type=refresh_token&refresh_token='.$token->refresh_token;
//转成对象
$access_token = json_decode(file_get_contents($access_token_url));
if (isset($access_token->errcode)) {
    echo '<h1>错误:</h1>'.$access_token->errcode;
    echo '<br/><h2>错误信息:</h2>'.$access_token->errmsg;
    exit;
}
$user_info_url = 'https://api.weixin.qq.com/sns/userinfo?access_token='.$access_token->access_token.'&openid='.$access_token->openid.'&lang=zh_CN';
//转成对象
$user_info = json_decode(file_get_contents($user_info_url));
if (isset($user_info->errcode)) {
    echo '<h1>错误:</h1>'.$user_info->errcode;
    echo '<br/><h2>错误信息:</h2>'.$user_info->errmsg;
    exit;
}
//打印用户信息
echo '<pre>';
print_r($user_info);
echo '</pre>';
?>

参数
描述
openid 用户的唯一标识
nickname 用户昵称
sex 用户的性别,值为1时是男性,值为2时是女性,值为0时是未知
province 用户个人资料填写的省份
city 普通用户个人资料填写的城市
country 国家,如中国为CN
headimgurl 用户头像,最后一个数值代表正方形头像大小(有0、46、64、96、132数值可选,0代表640*640正方形头像),用户没有头像时该项为空
privilege 用户特权信息,json 数组,如微信沃卡用户为(chinaunicom)
unionid 只有在用户将公众号绑定到微信开放平台帐号后,才会出现该字段。详见:获取用户个人信息(UnionID机制)

到此网页登陆授权开发功能就作完了,如果想要获取用户基本信息我们需要看另一个例子,在官方有说明大家可自行搜索哦。

PHP APC提供两种缓存功能,即缓存Opcode(目标文件),我们称之为apc_compiler_cache。同时它还提供一些接口用于PHP开发人员将用户数据驻留在内存中,我们称之为apc_user_cache,下面我们来看看PHP APC缓存安装配置.

最简单的方法,找到php安装目录的pecl

自动安装

# /usr/local/php/bin/pecl install apc

接下来按提示一步步完成即可

然后配置 /usr/local/php/etc/php.ini  末尾加入

extension=apc.so
 
手动安装

官网:http://cn2.php.net/manual/zh/book.apc.php
下载:http://pecl.php.net/package/APC 找最新的

下载apc

# wget http://pecl.php.net/get/APC-3.1.13.tgz
# tar -zxvf APC-3.1.13.tgz
# cd APC-3.1.13

生成configure文件

# /usr/local/php/bin/phpize

 执行configure 并且make && make install

# ./configure --enable-apc --enable-apc-mmap --with-php-config=/usr/local/php/bin/php-config
# make
# make install

拷贝添加SO文件

# cp /usr/local/php/lib/php/extensions/no-debug-non-zts-20100525/apc.so /usr/local/php/lib/php/extensions/apc.so
# chmod 755 /usr/local/php/lib/php/extensions/apc.so

 修改php.ini使之启动APC模块

# vi /usr/local/php/etc/php.ini
extension_dir = "/usr/local/php/lib/php/extensions"
extension=apc.so
apc.enabled = 1
; apc.cache_by_default = on
; apc.shm_segments = 1
; apc.shm_size = 128
; apc.ttl = 7200
; apc.user_ttl = 7200
; apc.num_files_hint = 1024
; apc.write_lock = On
; apc.gc_ttl=3600
; apc.ttl=0
; apc.mmap_file_mask=/tmp/apc.XXXXXX

 重启apache

# service httpd restart
 
使用APC

test.php

<?php
print_r(apc_cache_info());

注意 在浏览器看会不是很友好,可以查看网页源代码就看到很清晰

Array
(
    [num_slots] => 1031
    [ttl] => 0
    [num_hits] => 3
    [num_misses] => 1
    [num_inserts] => 1
    [expunges] => 0
    [start_time] => 1398341530
    [mem_size] => 4240
    [num_entries] => 1
    [file_upload_progress] => 1
    [memory_type] => mmap
    [locking_type] => pthread mutex Locks
    [cache_list] => Array
        (
            [0] => Array
                (
                    [type] => file
                    [device] => 64768
                    [inode] => 1179758
                    [filename] => /data/www/www.111cn.net /test.php
                    [num_hits] => 3
                    [mtime] => 1398341609
                    [creation_time] => 1398341617
                    [deletion_time] => 0
                    [access_time] => 1398341630
                    [ref_count] => 1
                    [mem_size] => 4240
                )
 
        )
 
    [deleted_list] => Array
        (
        )
 
    [slot_distribution] => Array
        (
            [109] => 1
        )
 
)

多次点击,可以发现 num_hits  在变化,说明缓存命中了!

压力测试看效果

关闭开启apc分别压力测试对比一下你会发现开启apc之后吞吐率会比没开启apc要提高许多。

# ab -n1000 -c10 http://www.111cn.net /test.php

本教程来详解Drupal的Authcache缓存模块的缓存机制原理。Drupal带有内置的缓存模块:Boost、Authcache,但是这两个模块的原理不同,boost是生成静态页面,Authcache是生存页面缓存。

相关文章:Drupal的模块高级应用之Authcache-动态加载内容教程

Authcache模块和Boost模块的原理不一样,Boost模块是生成静态页面,所以缓存的效果最好,速度最快。Authcache模块是利用Drupal自身的缓存机制,生成页面缓存,由于进入到了Drupal环节,因此速度没有Boost缓存快,但是优点就是可以灵活的使用PHP/Drupal相关方法,动态处理数据。

Drupal模块讲解-Authcache缓存原理详解教程


首先,我们从Drupal的bootstrap讲起。

function drupal_bootstrap($phase = NULL, $new_phase = TRUE) {
  // Not drupal_static(), because does not depend on any run-time information.
  static $phases = array(
    DRUPAL_BOOTSTRAP_CONFIGURATION,
    DRUPAL_BOOTSTRAP_PAGE_CACHE,
    DRUPAL_BOOTSTRAP_DATABASE,
    DRUPAL_BOOTSTRAP_VARIABLES,
    DRUPAL_BOOTSTRAP_SESSION,
    DRUPAL_BOOTSTRAP_PAGE_HEADER,
    DRUPAL_BOOTSTRAP_LANGUAGE,
    DRUPAL_BOOTSTRAP_FULL,
  );
….
}

这是Drupal自带的bootstrap的几个环节(Drupal7),从CONFIGURATION、一直到 FULL,这样整个Drupal就启动了,所有的模块也加载了。
其中我们发现,有一个环节叫 PAGE_CACHE,我们来把这个阶段的处理函数完整的贴出来,以便大家能更好的理解这段代码。

function _drupal_bootstrap_page_cache() {
  global $user;
 
  // Allow specifying special cache handlers in settings.php, like
  // using memcached or files for storing cache information.
  require_once DRUPAL_ROOT . '/includes/cache.inc';
  foreach (variable_get('cache_backends', array()) as $include) {
    require_once DRUPAL_ROOT . '/' . $include;
  }
  // Check for a cache mode force from settings.php.
  if (variable_get('page_cache_without_database')) {
    $cache_enabled = TRUE;
  }
  else {
    drupal_bootstrap(DRUPAL_BOOTSTRAP_VARIABLES, FALSE);
    $cache_enabled = variable_get('cache');
  }
  drupal_block_denied(ip_address());
  // If there is no session cookie and cache is enabled (or forced), try
  // to serve a cached page.
  if (!isset($_COOKIE[session_name()]) &amp;&amp; $cache_enabled) {
    // Make sure there is a user object because its timestamp will be
    // checked, hook_boot might check for anonymous user etc.
    $user = drupal_anonymous_user();
    // Get the page from the cache.
    $cache = drupal_page_get_cache();
    // If there is a cached page, display it.
    if (is_object($cache)) {
      header('X-Drupal-Cache: HIT');
      // Restore the metadata cached with the page.
      $_GET['q'] = $cache-&gt;data['path'];
      drupal_set_title($cache-&gt;data['title'], PASS_THROUGH);
      date_default_timezone_set(drupal_get_user_timezone());
      // If the skipping of the bootstrap hooks is not enforced, call
      // hook_boot.
      if (variable_get('page_cache_invoke_hooks', TRUE)) {
        bootstrap_invoke_all('boot');
      }
      drupal_serve_page_from_cache($cache);
      // If the skipping of the bootstrap hooks is not enforced, call
      // hook_exit.
      if (variable_get('page_cache_invoke_hooks', TRUE)) {
        bootstrap_invoke_all('exit');
      }
      // We are done.
      exit;
    }
    else {
      header('X-Drupal-Cache: MISS');
    }
  }
}

当我们看到最下面,exit ;(We are done)之处,我们就知道,Drupal已经处理完了请求,后面的环境(Session、数据库、模块、FULL)等环节就不用启动了,因此大大节省了服务器的处理时间和提高了响应时间。

这就是Drupal自带的缓存处理机制!!

Drupal自带的缓存机制缺点也很明显,就是只对匿名用户有效。

因此,Authcache模块就出现了,Authcache就是利用Drupal自带的缓存机制,实现对登录用户的缓存。

继续看上面的代码,其中有3行,如下:

foreach (variable_get('cache_backends', array()) as $include) {
  require_once DRUPAL_ROOT . '/' . $include;
}

其中,获取’cache_backends’的时候,加载了一个数组变量,所以在Drupal自身的缓存阶段要使用到authcache,那就必须修改这个 cache_backends。
果如其然,如下所示,我们在安装authcache的时候,就必须设置如下变量。

$conf['cache_backends'][] = 'sites/all/modules/authcache/authcache.cache.inc';
$conf['cache_backends'][] = 'sites/all/modules/authcache/modules/authcache_builtin/authcache_builtin.cache.inc';

这个时候,我们就加载进了authcache.cache.inc和文件了。

继续…
我们打开authcache.cache.inc 其中,就是定义一些函数。
继续查看authcache_builtin.cache.inc文件,看到如下代码:

$delivered = authcache_builtin_cacheinc_retrieve_cache_page();
if ($delivered) {
  exit;
}

也就是说在这个时候,如果命中了缓存就直接输入页面内容,不再继续boot!这个地方也就代替了原本Drupal自己查找缓存和计算命中缓存的逻辑,使用authcache自己的算法,根据用户的角色不同,使用的缓存不同。
这就是authcache的核心!

当然authcache还可以做更多,比如,
1. 根据用户不同,生产不同的缓存(需要处理)。
2. 配合authcache_p13n模块,动态处理某些局部页面,比如某个block。
3. 修改缓存的某个些内容。(稍后会详细讲解)
等等,这就是authcache比boost灵活的地方,当然也是缺点,需要调用很多PHP、数据库等等,肯定比boost慢一些。

[!--infotagslink--]

相关文章

  • 源码分析系列之json_encode()如何转化一个对象

    这篇文章主要介绍了源码分析系列之json_encode()如何转化一个对象,对json_encode()感兴趣的同学,可以参考下...2021-04-22
  • 不打开网页直接查看网站的源代码

      有一种方法,可以不打开网站而直接查看到这个网站的源代码..   这样可以有效地防止误入恶意网站...   在浏览器地址栏输入:   view-source:http://...2016-09-20
  • php中去除文字内容中所有html代码

    PHP去除html、css样式、js格式的方法很多,但发现,它们基本都有一个弊端:空格往往清除不了 经过不断的研究,最终找到了一个理想的去除html包括空格css样式、js 的PHP函数。...2013-08-02
  • php 调用goolge地图代码

    <?php require('path.inc.php'); header('content-Type: text/html; charset=utf-8'); $borough_id = intval($_GET['id']); if(!$borough_id){ echo ' ...2016-11-25
  • JS基于Mootools实现的个性菜单效果代码

    本文实例讲述了JS基于Mootools实现的个性菜单效果代码。分享给大家供大家参考,具体如下:这里演示基于Mootools做的带动画的垂直型菜单,是一个初学者写的,用来学习Mootools的使用有帮助,下载时请注意要将外部引用的mootools...2015-10-23
  • JS+CSS实现分类动态选择及移动功能效果代码

    本文实例讲述了JS+CSS实现分类动态选择及移动功能效果代码。分享给大家供大家参考,具体如下:这是一个类似选项卡功能的选择插件,与普通的TAb区别是加入了动画效果,多用于商品类网站,用作商品分类功能,不过其它网站也可以用,...2015-10-21
  • JS实现自定义简单网页软键盘效果代码

    本文实例讲述了JS实现自定义简单网页软键盘效果。分享给大家供大家参考,具体如下:这是一款自定义的简单点的网页软键盘,没有使用任何控件,仅是为了练习JavaScript编写水平,安全性方面没有过多考虑,有顾虑的可以不用,目的是学...2015-11-08
  • php 取除连续空格与换行代码

    php 取除连续空格与换行代码,这些我们都用到str_replace与正则函数 第一种: $content=str_replace("n","",$content); echo $content; 第二种: $content=preg_replac...2016-11-25
  • php简单用户登陆程序代码

    php简单用户登陆程序代码 这些教程很对初学者来讲是很有用的哦,这款就下面这一点点代码了哦。 <center> <p>&nbsp;</p> <p>&nbsp;</p> <form name="form1...2016-11-25
  • PHP传值到不同页面的三种常见方式及php和html之间传值问题

    在项目开发中经常见到不同页面之间传值在web工作中,本篇文章给大家列出了三种常见的方式。接触PHP也有几个月了,本文总结一下这段日子中,在编程过程里常用的3种不同页面传值方法,希望可以给大家参考。有什么意见也希望大...2015-11-24
  • PHP实现清除wordpress里恶意代码

    公司一些wordpress网站由于下载的插件存在恶意代码,导致整个服务器所有网站PHP文件都存在恶意代码,就写了个简单的脚本清除。恶意代码示例...2015-10-23
  • js修改input的type属性问题探讨

    js修改input的type属性有些限制。当input元素还未插入文档流之前,是可以修改它的值的,在ie和ff下都没问题。但如果input已经存在于页面,其type属性在ie下就成了只读属性了,不可以修改。...2013-10-19
  • Mysql常见问题集锦

    1,utf8_bin跟utf8_general_ci的区别 ci是 case insensitive, 即 "大小写不敏感", a 和 A 会在字符判断中会被当做一样的; bin 是二进制, a 和 A 会别区别对待. 例如你运行: SELECT * FROM table WHERE txt = 'a'...2013-10-04
  • js识别uc浏览器的代码

    其实挺简单的就是if(navigator.userAgent.indexOf('UCBrowser') > -1) {alert("uc浏览器");}else{//不是uc浏览器执行的操作}如果想测试某个浏览器的特征可以通过如下方法获取JS获取浏览器信息 浏览器代码名称:navigator...2015-11-08
  • JS实现双击屏幕滚动效果代码

    本文实例讲述了JS实现双击屏幕滚动效果代码。分享给大家供大家参考,具体如下:这里演示双击滚屏效果代码的实现方法,不知道有觉得有用处的没,现在网上还有很多还在用这个特效的呢,代码分享给大家吧。运行效果截图如下:在线演...2015-10-30
  • index.php怎么打开?如何打开index.php?

    index.php怎么打开?初学者可能不知道如何打开index.php,不会的同学可以参考一下本篇教程 打开编辑:右键->打开方式->经文本方式打开打开运行:首先你要有个支持运行PH...2017-07-06
  • JS日期加减,日期运算代码

    一、日期减去天数等于第二个日期function cc(dd,dadd){//可以加上错误处理var a = new Date(dd)a = a.valueOf()a = a - dadd * 24 * 60 * 60 * 1000a = new Date(a)alert(a.getFullYear() + "年" + (a.getMonth() +...2015-11-08
  • PHP开发微信支付的代码分享

    微信支付,即便交了保证金,你还是处理测试阶段,不能正式发布。必须到你通过程序测试提交订单、发货通知等数据到微信的系统中,才能申请发布。然后,因为在微信中是通过JS方式调用API,必须在微信后台设置支付授权目录,而且要到...2014-05-31
  • Mysql大小写敏感的问题

    一、1 CREATE TABLE NAME(name VARCHAR(10)); 对这个表,缺省情况下,下面两个查询的结果是一样的:复制代码 代码如下: SELECT * FROM TABLE NAME WHERE name='clip'; SELECT * FROM TABLE NAME WH...2015-03-15
  • PHP常用的小程序代码段

    本文实例讲述了PHP常用的小程序代码段。分享给大家供大家参考,具体如下:1.计算两个时间的相差几天$startdate=strtotime("2009-12-09");$enddate=strtotime("2009-12-05");上面的php时间日期函数strtotime已经把字符串...2015-11-24