-
2020-12-20 02:31:32
解一个问题有H个苹果放到P个篮子里,苹果有标号,从1-H,且要求的结果是每个篮子都有苹果,苹果的标号要从小到大,且如果篮子中的数目不平均的话,要差值最小
大概是在各个样子
1.
1 2 3
2.
4 5 6
3.
。。。。H
首先要确定怎么个放置的方法
用取余的方法,先确定每个篮子至少放多少个,取模不为0的话,将取模的值就是要多出1个苹果的篮子数,这样就可以计算出具体要怎么放
private function generatemap($lessonnum, $days){
$step2 = intval($lessonnum/$days);
$d1 = $lessonnum%$days;
$d2 = $days - $d1;
$step1 = $step2 + 1;
return array($d1."1" => $step1 , $d2."2" => $step2);//加一个标识,防止d1 等于 d2
}
下面就是放置的问题
$q = 0;
$atag = 1;
foreach($map as $k => $v){
$k = substr($k,0,-1);
if(!($k == 0 or $v ==0)){
for($i = 0; $i < $k; $i++){//天数
for($z = 0;$z < $v; $z++ ){//课数
$temp[$i.$atag]['m'] = dayafter($i+1);
$temp[$i.$atag]['tag'] = $i;
$temp[$i.$atag]['info'][] = $lessons[$q];
$q = $q + 1;
}
}
}
$atag += 1;
}
这样temp就分成了理想的结构
info的子集就是每个篮子中的苹果
这么算是不是很笨?有没有更好的算法?
转载请注明本文链接:http://www.simapple.com/224.html
更多相关内容 -
PHP 分配问题,怎么实现最优分配呢?
2021-01-12 08:43:34结果模拟 第一小组 第一天 第一小组第二天 1实验台 8点-10点 3实验台 4实验台 10点-11点 4实验台 5实验台 13点-18点 第二小组 第二小组第二天 2实验台 8-11 1实验 4实验台 11-12 5实验 3实验台 13-17 我实现了分配,...1、把人员分成 20组
2、5个实验台
1 实验台需要2小时
2 实验台需要 3小时
3 实验台需要 4小时
4 实验台需要 1小时
5 实验台需要 5小时
3、每个实验台 每个小组必须都做一遍。
4、一天做不完,可以推到第二天,第二天完不成可以再推 等等
5、第一小组占用实验台 ,第二小组可以选择别的实验台,第三小组等等类推
6、假设 2017-11-1日开始
假如上午8点开始 12点结束
假如下午13点开始 18点结束
结果模拟
第一小组 第一天 第一小组第二天
1实验台 8点-10点 3实验台
4实验台 10点-11点 4实验台
5实验台 13点-18点
第二小组 第二小组第二天
2实验台 8-11 1实验
4实验台 11-12 5实验
3实验台 13-17
我实现了分配,但是存在问题,不能达到最优分配
代码如下,
class Demo extends Basic
{
public $days = array();
public $content = array();
public $run_date = '2017-10-01 08:00';
public $run_date_n = '2017-10-01 13:00';
public $run_group = 1;
public $run_room = array();
public $run_content = array();
public $run_noon_m = '240';
public $run_after_noon_m = '300';
public $run_ext_content = null;
function __construct()
{
parent::__construct();
}
function combination()
{
$this->content = array(
24 => '180',
25 => '120',
26 => '240',
27 => '60',
28 => '300'
);
// // 第一组
$this->run_content = $this->content;
$this->run_ext_content = null;
$this->_get_days();
var_dump($this->days);
$this->days = array();
}
private function _get_days()
{
$day_list = $this->_get_day();
$other = $this->_check_ext_content();
$this->days[] = $day_list;
if (!empty($other)) {
$this->run_date = date('Y-m-d H:i', (strtotime($this->run_date) + 86400));
$this->run_date_n = date('Y-m-d H:i', (strtotime($this->run_date_n) + 86400));
$this->run_content = $other;
return $this->_get_days();
}
if (!empty($this->run_content)) {
return $this->_get_days();
}
}
private function _get_day()
{
$this->_check_content();
$_noon = $this->_get_most_noon();
$this->_check_content();
$_after_noon = $this->_get_most_afternoon();
return array(
'date_noon' => $this->run_date,
'date_afternoon' => $this->run_date_n,
'noon' => $_noon,
'after_noon' => $_after_noon
);
}
private function _get_most_noon()
{
if (!empty($this->run_content)) {
$list = $this->_get_combination($this->run_content, $this->run_noon_m);
if (!empty($list)) {
$frist = each($list);
// 验证最优安排时间是否被占用
if (!empty($this->run_room)) {
$keys = explode('|', $frist['key']);
foreach ($keys as $room) {
if (!empty($this->run_room[$room])) {
$_end = (strtotime($this->run_date) + $this->content[$room] * 60);
$run_noon = $this->run_date . '|' . date('Y-m-d H:i', $_end);
if (in_array($run_noon, $this->run_room[$room]) === true) {
unset($this->run_content[$room]);
return $this->_get_most_noon();
}
}
}
$this->run_ext_content .= $this->run_ext_content === null ? $frist['key'] : '|' . $frist['key'];
return $frist['key'];
} else {
$this->run_ext_content .= $this->run_ext_content === null ? $frist['key'] : '|' . $frist['key'];
return $frist['key'];
}
}
}
}
private function _get_most_afternoon()
{
if (!empty($this->run_content)) {
$list = $this->_get_combination($this->run_content, $this->run_after_noon_m);
if (!empty($list)) {
$frist = each($list);
// 验证最优安排时间是否被占用
if (!empty($this->run_room)) {
$keys = explode('|', $frist['key']);
foreach ($keys as $room) {
if (!empty($this->run_room[$room])) {
$_end = (strtotime($this->run_date_n) + $this->content[$room] * 60);
$run_afternoon = $this->run_date_n . '|' . date('Y-m-d H:i', $_end);
if (in_array($run_afternoon, $this->run_room[$room]) === true) {
unset($this->run_content[$room]);
return $this->_get_most_afternoon();
}
}
}
$this->run_ext_content .= $this->run_ext_content === null ? $frist['key'] : '|' . $frist['key'];
return $frist['key'];
} else {
$this->run_ext_content .= $this->run_ext_content === null ? $frist['key'] : '|' . $frist['key'];
return $frist['key'];
}
}
}
}
private function _get_combination($lists, $like)
{
$_combination = array();
if (!empty($lists) && !empty($like)) {
$combination_list = \Math\Combinatorics\Combination::get($lists);
foreach ($combination_list as $item) {
$_sum_time = 0;
$_c_ids = null;
foreach ($item as $_c_id => $_c_tiem) {
$_sum_time += $_c_tiem;
$_c_ids .= $_c_ids === null ? $_c_id : '|' . $_c_id;
}
$_combination[$_c_ids] = $like - $_sum_time;
}
foreach ($_combination as $key => $item) {
if ($item < 0) {
unset($_combination[$key]);
}
}
asort($_combination);
return $_combination;
}
return $_combination;
}
private function _check_ext_content()
{
$used = explode('|', $this->run_ext_content);
$content = $this->content;
foreach ($used as $_key) {
unset($content[$_key]);
}
return $content;
}
private function _check_content()
{
if (!empty($this->run_ext_content)) {
$used = explode('|', $this->run_ext_content);
foreach ($used as $_key) {
unset($this->run_content[$_key]);
}
}
return false;
}
}
哪位大神有思路,望指点一二。
-
php队列的实现思路和详细过程
2020-12-20 02:31:29php cron_mission.php >> cron_mission.log #可以先使用crontab -l查看本机已经使用的定时任务 九、服务器部署二:写定时任务调度程序 思路:将定时任务写入到任务调度程序cron_mission.php中,这样可以在cron_...一:队列场景
当我们使用某讯或者某浪的邮箱时,点击群发邮件之后,只需等待很短的时间,浏览器 提示提交成功,正在发送之类的信息时,用户就可以关掉浏览器,稍后,收件地址栏里的邮箱将陆续收到该群发邮件,再比如群发定时邮件,以及当商城系统中有客 户下单,客户,客服,仓库等相关人员收到订单邮件信息。诸如此类,队列的应用范围是如此之广。
二:普通工程师的解决方案和架构师的解决方案
方案1:建表存邮件,消息等,用定时程序取出发送。
方案2:抽象到更高一层,开发一套通用异步处理队列适用于任何复杂的业务逻辑
那么,作为架构师,使用队列的做法,将抽象层和业务层分离,可具有良好的扩展性和可维护性。相比较而言就高明了许多,
下面就我们介绍一下自定义队列的实现思路和方法。
三 :队列总体设计
1:需要队列程序,提供加入队列接口和取队列接口等
2:需要存储队列,文件或者数据库
3:需要定时程序取出队列并执行
4:其它扩展功能:优先级,日志,定时等
代码的目录结构如下,每个文件的作用用//注释来标明
|–addTask.php //添加任务到队列的例子
|–cronMission.php //定时任务调度程序,例如linux中受crontab
直接调用的文件,业务逻辑工程师可以在这个文件中灵活定义自己的队列任务,从而不用每个队列任务 都需要上服务器修改crontab,从而在安全性,便捷性方面有很大提高
|–db.php //数据库操作
|–db.sql //建立队列需要用到的基本表结构
|–doQueue.php //执行队列任务
|–Queue.class.php //队列核心业务在这里定义,包括将任务加入队列,读队列,更改队列任务状态
|–sendMsg.php //队列要实现具体任务的业务接口,比如现有系统的发送消息的接口,这里例子中因为将此队列程序和现有系统系统集成,用写入日志来演示
四 :队列具体实现一:建任务存储表
1:先来个最基本的:
CREATE TABLE`queue` (
id int(11) NOT NULL auto_increment primarykey,
taskphp varchar(128) NOT NULL default '',
param text not null default '',
status tinyint not null default 0,
ctime timestamp NOT NULL default CURRENT_TIMESTAMP,
KEY (ctime)
) ENGINE=InnoDBDEFAULT CHARSET=utf8;
字段解释:
taskphp:处理业务的接口文件
param:处理业务的接口文件需要接收的参数
status:任务处理状态,0为未处理,处理完毕更改为1
五 、队列具体实现二:定义调用接口
/*** @author:cyw0413* 任务队列实现* date:2018-11-01*/
include_once('db.php');
class Queue
{
/*** 把任务扔到队列** @param string $taskphp 执行任务的程序* @param string $param 执行任务程序所用的参数* 例如,群发消息加入队列:* $arr = array(* "uid" => 4,//发信息的人的UID* "uids" => array(6,234,34,67,7888,2355), //接收信息的人的UID* "content" => 'xxxxx',//信息内容* );* $cqueue = new Queue();* $cqueue->add("/app/send_msg.php", serialize($arr));**/
public function add($taskphp,$param)
{
$taskphp = mysql_real_escape_string($taskphp);
//$param = mysql_real_escape_string($param);
$param = $param;
$sql = "insert into queue (taskphp, param) values('".$taskphp."', '".$param."')";
$re = execute($sql);
if ($re){
$pid = mysql_insert_id();
return $pid;
}else{
return false;
}
}
/*** 读取任务队列** @param string $limit 一次取多少条*/
public function getQueueTask($limit = 1000)
{
$limit = (int)$limit;
$sql = "select id, taskphp, param from queue where status = 0 order by id asc";
$re = query($sql);
return $re;
}
/*** 更新任务状态** @param string $limit 一次取多少条*/
public function updateTaskByID($id)
{
$id = (int)$id;
$mtime = time();
$sql = "update queue set status =1, mtime = ".$mtime." where id = ".$id;
$re = execute($sql);
return $re;
}
public static function a2s($arr)
{
$str = "";
foreach ($arr as $key => $value){
if (is_array($value)){
foreach ($value as $value2){
$str .= urlencode($key) . "[]=" . urlencode($value2) . "&";
}
}else{
$str .= urlencode($key) . "=" . urlencode($value) . "&";
}
}
return $str;
}
public static function s2a($str){
$arr = array();
parse_str($str, $arr);
return $arr;
}
}
?>
1:加入队列接口
l //$param1 为执行任务的程序,$param2 为程序参数,可以为序列化的数据
l $cqueue->add($param1,$param2);
2: 读取队列接口
l $tasks = $cqueue->getQueueTask($limit = 1000);
3:更新任务状态
l $cqueue->updateTaskStatus($id);
4:a2s是自定义的一个数组转换字符串方法,这里不要使用json_encode,容易出现问题,同样,从数据库中取出转换为数组的时候,使用s2a方法
l $re = $cqueue->add("sendMsg.php", Queue::a2s($arr));
六、队列具体实现三:写执行队列的程序
根据设计,执行队列的程序文件是 do_queue.php , 它的主要功能是把任务从队列表里取出来,并且在后台执行。
do_queue.php部分代码:
$phpcmd = exec("which php"); //查找到php安装位置$cqueue = new Queue();
$tasks = $cqueue->getQueueTask(200);
foreach ($tasks as $t){
$taskphp = $t['taskphp'];
$param = $t['param'];
$job = $phpcmd . " " . escapeshellarg($taskphp) . " " . escapeshellarg($param);
system($job);
七、具体任务的业务实现
还是拿群发消息来做例子,我们需要写好一个群发消息的程序,这个程序接收事先定义好的参数,然后根据参数调用发消息的接口把消息发送出去。
这个一般由做业务功能的工程师实现。但是架构师事先得写文档例子,教会别人使用。
send_msg.php:
$para = $argv[1];
$arr = unserialize($para);
$cmessage = new Message();
foreach($arr['uids'] as $touid){
$cmessage->send($arr['uid'], $touid, $arr['content']);
}
八、服务器部署一:配置crontab
咱们执行队列的程序都写好了, 这个程序怎么触发呢,当然就要用到linux的定时任务,每隔一定的时间,执行do_queue.php一次。但是呢,这里不是直接调用 do_queue.php,咱们再提高一层,加个调度程序cron_mission.php, 在cron_mission.php里面调用do_queue.php
配置定时任务 crontab:
l crontab –e
l * * * * * cd /ucai/schedule;php cron_mission.php >> cron_mission.log
#可以先使用crontab -l查看本机已经使用的定时任务
九、服务器部署二:写定时任务调度程序
思路:将定时任务写入到任务调度程序cron_mission.php中,这样可以在cron_mission.php中灵活控制队列任务。相比较直接通 过crontab控制doQueue.php而言,避免了频繁修改服务器上的crontab,从安全,便于维护等角度来说,都是上策。
cron_mission.php 示例:
if ($minute % 5 == 0){
if(chdir($site_dir."app/")) {
$cmd = "$phpcmddo_queue.php > do_queue.log &";
echo '[' , $ymd , ' ' , $hour , ':' , $minute , '] ' , $cmd , "n";
system($cmd);
}
}
十、开启多进程并发执行队列
思路:对任务序列进行编号,数据库中执行的时候
where条件加上id%每个队列要执行任务总数=队列编号
这样可以避免重复处理
例如:每个进程执行10条任务,修改如下
1:定时任务的修改
修改前:
if ($minute % 5 == 0){
if(chdir($site_dir."app/")) {
$cmd = "$phpcmddo_queue.php > do_queue.log &";
echo '[' , $ymd , ' ' , $hour , ':' , $minute , '] ' , $cmd , "n";
system($cmd);
}
}
修改后:
if ($minute % 5 == 0){
for ($i=0; $i < 10; $i++) {
$cmd = "$phpcmddoQueue.php 10$i>> doQueueMission".date('Y-m-d').".log ";
echo date("Y-m-d H:i:s") . "t : " .$cmd."n";
system($cmd);
}
}
//每次进行10个进程,$i来区分是当前的进程标示
2:队列执行程序的修改
修改前:
$phpcmd = 'D:workwampbinphpphp5.3.10php ';
$cqueue = new Queue();
$tasks = $cqueue->getQueueTask(200);
修改后:
$phpcmd = 'D:workwampbinphpphp5.3.10php ';
$total=$argv[1];
$i=$argb[2];
$cqueue = new Queue();
$tasks = $cqueue->getQueueTask($total,$i,200);
3:取队列接口的修改
修改前:
public function getQueueTask($limit = 1000)
{
$limit = (int)$limit;
$sql = "select id, taskphp, param from queue where status = 0 order by id asc";
$re = query($sql);
return $re;
}
修改后:
public function getQueueTask($total,$i,$limit = 1000)
{
$limit = (int)$limit;
$sql = "select id, taskphp, param from queue where status = 0 and id%$total=$iorder by id asc";
$re = query($sql);
return $re;
}
4:需要关注服务器压力
进程数定为多少,取决于服务器压力
十一、实现任务优先级
1:任务存储表加优先级字段
在数据表里,加一个优先级字段,按字段值的数值大小来区分优先级
2:修改取队列任务接口,按优先级取
同样是在sql语句中增加order by
十二、记录队列日志
1:关键地方加echo
2:shell脚本的>>和>的各自作用
总结:
我们这里的队列实现借助了服务器的计划任务来实现,例如linux中的crontab,这本身是linux系统中的一个程序,平时我们还可以使用他来进行 定时执行.sh脚本,例如将数据库备份打包并ftp传送到指定服务器上,这个功能不需要借助php脚本,直接用.sh脚本就可以实现。在这里我们巧妙的将 crontab和php脚本结合,并且使用crontab来不断调用一个队列调度接口cronMission.php,再通过 cronMission.php直接来控制具体什么时候或者是满足什么条件来执行什么队列任务。
这里面几个需要注意的地方
1:往数据库中存取数据时,不要直接使用json_encode或者json_decode,容易造成一些意外问题,在代码中,我们定义了a2s和s2a两个方法,分别是处理数组转为字符串,和从数据库中读取字符串后转为数组。
2:当任务量比较大,同时服务器负载又没有充分利用的时候,可以使用多进程并发处理,在并发处理的时候需要考虑一个问题,就是如何避免重复,在这里我们使 用了,对队列任务进行标记,每次从数据库中读取一个进程需要处理的一批任务,使用数据库中id与批次标示取余等于0的方法来区分,避免不同批次的队列,重 复处理相同任务。(上面步骤10中有具体实现)以上内容希望帮助到大家,很多PHPer在进阶的时候总会遇到一些问题和瓶颈,业务代码写多了没有方向感,不知道该从那里入手去提升,对此我整理了一些资料,包括但不限于:分布式架构、高可扩展、高性能、高并发、服务器性能调优、TP6,laravel,YII2,Redis,Swoole、Swoft、Kafka、Mysql优化、shell脚本、Docker、微服务、Nginx等多个知识点高级进阶干货需要的可以免费分享给大家或者请看个人主页以及知乎专栏PHP7进阶架构师zhuanlan.zhihu.com
来源:https://www.cnblogs.com/yingmo/p/6148380.html
-
PHP实现执行定时任务的几种思路详解
2020-12-20 02:31:21本文,我们就来深入的解析几种常见的php定时任务的思路。Linux服务器上使用CronTab定时执行php我们先从相对比较复杂的服务器执行php谈起。服务器上安装了php,就可以执行php文件,无论是否安装了nginx或Apache这样的...PHP本身是没有定时功能的,PHP也不能多线程。PHP的定时任务功能必须通过和其他工具结合才能实现,例如WordPress内置了wp-cron的功能,很厉害。本文,我们就来深入的解析几种常见的php定时任务的思路。
Linux服务器上使用CronTab定时执行php
我们先从相对比较复杂的服务器执行php谈起。服务器上安装了php,就可以执行php文件,无论是否安装了nginx或Apache这样的服务器环境软件。而Linux中,使用命令行,用CronTab来定时任务,又是绝佳的选择,而且也是效率最高的选择。
首先,进入命令行模式。作为服务器的linux一般都默认进入命令行模式的,当然,我们管理服务器也一般通过putty等工具远程连接到服务器,为了方便,我们用root用户登录。在命令行中键入:
crontab -e
之后就会打开一个文件,并且是非编辑状态,则是vi的编辑界面,通过敲键盘上的i,进入编辑模式,就可以编辑内容。这个文件中的每一行就是一个定时任务,我们新建一行,就是新建一条定时任务(当然是指这一行内按照一定的格式进行书写)。我们现在来举个例子,增加一行,内容如下:
00 * * * * lynx -dump https://www.yourdomain.com/script.php
这是什么意思呢?实际上上面这一行由两部分组成,前面一部分是时间,后面一部分是操作内容。例如上面这个,
00 * * * *
就是指当当前时间的分钟数为00时,执行该定时任务。时间部分由5个时间参数组成,分别是:
分 时 日 月 周
第1列表示分钟1~59 每分钟用或者 */1表示,/n表示每n分钟,例如*/8就是每8分钟的意思,下面也是类推
第2列表示小时1~23(0表示0点)
第3列表示日期1~31
第4列表示月份1~12
第5列标识号星期0~6(0表示星期天)
整个句子的后面部分就是操作的具体内容。
lynx -dump https://www.yourdomain.com/script.php
意思就是说通过lynx访问这个url。我们在使用中主要用到lynx、curl、wget来实现对url的远程访问,而如果要提高效率,直接用php去执行本地php文件是最佳选择,例如:
00 */2 * * * /usr/local/bin/php /home/www/script.php
这条语句就可以在每2小时的0分钟,通过linux内部php环境执行script.php,注意,这里可不是通过url访问,通过服务器环境来执行哦,而是直接执行,因为绕过了服务器环境,所以效率当然要高很多。
好了,已经添加了几条需要的定时任务了吧。点击键盘上的Esc键,输入“:wq”回车,这样就保存了设置的定时任务,屏幕上也能看到提示创建了新的定时任务。接下来就是好好写你的script.php了。
关于CronTab的更多用法这里就不介绍了,如果你想更灵活的使用这个定时任务功能,应该自己再去深入学习一下crontab。
Windows服务器上使用bat定时执行php
windows上和linux上有一个类似的cmd和bat文件,bat文件类似于shell文件,执行这个bat文件,就相当于依次执行里面的命令(当然,还可以通过逻辑来实现编程),所以,我们可以利用bat命令文件在windows服务器上面实现PHP定时任务。实际上在windows上定时任务,和linux上道理是一样的,只不过方法和途径不同。好了下面开始。
首先,在一个你觉得比较适当的位置创建一个cron.bat文件,然后用文本编辑器打开它(记事本都可以),在里面写上这样的内容:
D:\php\php.exe -q D:\website\test.php
这句话的意思就是,使用php.exe去执行test.php这个php文件,和上面的contab一样,绕过了服务器环境,执行效率也比较高。写好之后,点击保存,关闭编辑器。
接下来就是设置定时任务来运行cron.bat。依次打开:“开始–>控制面板–>任务计划–>添加任务计划”,在打开的界面中设置定时任务的时间、密码,通过选择,把cron.bat挂载进去。确定,这样一个定时任务就建立好了,在这个定时任务上右键,运行,这个定时任务就开始执行了,到点时,就会运行cron.bat处理,cron.bat再去执行php。
非自有服务器(虚拟主机)上实现php定时任务
如果站长没有自己的服务器,而是租用虚拟主机,就无法进入服务器系统进行上述操作。这个时候应该如何进行php定时任务呢?其实方法又有多个。
使用ignore_user_abort(true)和sleep死循环
在一个php文档的开头直接来一句:
ignore_user_abort(true);
这时,通过url访问这个php的时候,即使用户把浏览器关掉(断开连接),php也会在服务器上继续执行。利用这个特性,我们可以实现非常牛的功能,也就是通过它来实现定时任务的激活,激活之后就随便它自己怎么办了,实际上就有点类似于后台任务。
而sleep(n)则是指当程序执行到这里时,暂时不往下执行,而是休息n秒钟。如果你访问这个php,就会发现页面起码要加载n秒钟。实际上,这种长时间等待的行为是比较消耗资源的,不能大量使用。
那么定时任务到底怎么实现呢?使用下面的代码即可实现:
ignore_user_abort(true);
set_time_limit(0);
date_default_timezone_set('PRC'); // 切换到中国的时间
$run_time = strtotime('+1 day'); // 定时任务第一次执行的时间是明天的这个时候
$interval = 3600*12; // 每12个小时执行一次
if(!file_exists(dirname(__FILE__).'/cron-run')) exit(); // 在目录下存放一个cron-run文件,如果这个文件不存在,说明已经在执行过程中了,该任务就不能再激活,执行第二次,否则这个文件被多次访问的话,服务器就要崩溃掉了
do {
if(!file_exists(dirname(__FILE__).'/cron-switch')) break; // 如果不存在cron-switch这个文件,就停止执行,这是一个开关的作用
$gmt_time = microtime(true); // 当前的运行时间,精确到0.0001秒
$loop = isset($loop) && $loop ? $loop : $run_time - $gmt_time; // 这里处理是为了确定还要等多久才开始第一次执行任务,$loop就是要等多久才执行的时间间隔
$loop = $loop > 0 ? $loop : 0;
if(!$loop) break; // 如果循环的间隔为零,则停止
sleep($loop);
// ...
// 执行某些代码
// ...
@unlink(dirname(__FILE__).'/cron-run'); // 这里就是通过删除cron-run来告诉程序,这个定时任务已经在执行过程中,不能再执行一个新的同样的任务
$loop = $interval;
} while(true);
通过执行上面这段php代码,即可实现定时任务,直到你删除cron-switch文件,这个任务才会停止。
但是有一个问题,也就是如果用户直接访问这个php,实际上没有任何作用,页面也会停在这个地方,一直处于加载状态,有没有一种办法可以消除这种影响呢?fsockopen帮我们解决了这个问题。
fsockopen可以实现在请求访问某个文件时,不必获得返回结果就继续往下执行程序,这是和curl通常用法不一样的地方,我们在使用curl访问网页时,一定要等curl加载完网页后,才会执行curl后面的代码,虽然实际上curl也可以实现“非阻塞式”的请求,但是比fsockopen复杂的多,所以我们优先选择fsockopen,fsockopen可以在规定的时间内,比如1秒钟以内,完成对访问路径发出请求,完成之后就不管这个路径是否返回内容了,它的任务就到这里结束,可以继续往下执行程序了。利用这个特性,我们在正常的程序流中加入fsockopen,对上面我们创建的这个定时任务php的地址发出请求,即可让定时任务在后台执行。如果上面这个php的url地址是www.yourdomain.com/script.php,那么我们在编程中,可以这样:
// ...
// 正常的php执行程序
// ..
// 远程请求(不获取内容)函数,下面可以反复使用
function _sock($url) {
$host = parse_url($url,PHP_URL_HOST);
$port = parse_url($url,PHP_URL_PORT);
$port = $port ? $port : 80;
$scheme = parse_url($url,PHP_URL_SCHEME);
$path = parse_url($url,PHP_URL_PATH);
$query = parse_url($url,PHP_URL_QUERY);
if($query) $path .= '?'.$query;
if($scheme == 'https') {
$host = 'ssl://'.$host;
}
$fp = fsockopen($host,$port,$error_code,$error_msg,1);
if(!$fp) {
return array('error_code' => $error_code,'error_msg' => $error_msg);
}
else {
stream_set_blocking($fp,true);//开启了手册上说的非阻塞模式
stream_set_timeout($fp,1);//设置超时
$header = "GET $path HTTP/1.1\r\n";
$header.="Host: $host\r\n";
$header.="Connection: close\r\n\r\n";//长连接关闭
fwrite($fp, $header);
usleep(1000); // 这一句也是关键,如果没有这延时,可能在nginx服务器上就无法执行成功
fclose($fp);
return array('error_code' => 0);
}
}
_sock('www.yourdomain.com/script.php');
// ...
// 继续执行其他动作
// ..
把这段代码加入到某个定时任务提交结果程序中,在设置好时间后,提交,然后执行上面这个代码,就可以激活该定时任务,而且对于提交的这个用户而言,没有任何页面上的堵塞感。
借用用户的访问行为来执行某些延迟任务
但是上面使用sleep来实现定时任务,是效率很低的一种方案。我们希望不要使用这种方式来执行,这样的话就可以解决效率问题。我们借用用户访问行为来执行任务。用户对网站的访问其实是一个非常丰富的行为资源,包括搜索引擎蜘蛛对网站的访问,都可以算作这个类型。在用户访问网站时,内部加一个动作,去检查任务列表中是否存在没有被执行的任务,如果存在,就将这个任务执行。对于用户而言,利用上面所说的fsockopen,根本感觉不到自己的访问竟然还做出了这样的贡献。但是这种访问的缺点就是访问很不规律,比如你希望在凌晨2点执行某项任务,但是这个时间段非常倒霉,没有用户或任何行为到达你的网站,直到早上6点才有一个新访问。这就导致你原本打算2点执行的任务,到6点才被执行。
这里涉及到一个定时任务列表,也就是说你需要有一个列表来记录所有任务的时间、执行什么内容。一般来说,很多系统会采用数据库来记录这些任务列表,比如wordpress就是这样做的。我则利用文件读写特性,提供了托管在github上的开源项目php-cron,你可以去看看。总之,如果你想要管理多个定时任务,靠上面的单个php是无法合理布局的,必须想办法构建一个schedules列表。由于这里面的逻辑比较复杂,就不再详细阐述,我们仅停留在思路层面上。
借用第三方定时任务跳板
很好玩的是,一些服务商提供了各种类型的定时任务,例如阿里云的ACE提供了单独的定时任务,你可以填写自己应用下的某个uri。百度云BCE提供了服务器监测功能,每天会按照一定的时间规律访问应用下的固定uri。类似的第三方平台上还有很多定时任务可以用。你完全可以用这些第三方定时任务作为跳板,为你的网站定时任务服务。比如说,你可以在阿里云ACE上建立一个每天凌晨2点的定时任务,执行的uri是/cron.php。然后你创建一个cron.php,里面则采用fsockopen去访问你真正要执行某些任务的网站的url,例如上面的www.yourdomain.com/script.php,而且在cron.php中还可以访问多个url。然后把cron.php上传到你的ACE上面去,让ACE的定时任务去访问/cron.php,然后让cron.php去远程请求目标网站的定时任务脚本。
循环利用include包含文件(待验证)
php面向过程的特性使得其程序是从上往下执行的,利用这个特性,在我们使用include某个文件时,就会执行被引入的文件,知道include的文件内程序执行完之后,再往下执行。如果我们创建一个循环,再利用sleep,不断的include某个文件,使循环执行某段程序,则可以达到定时执行的目的。我们再进一步,并不是利用while(true)来实现循环,而是利用被include文件本身再include自身来实现循环,比如我们创建一个do.php,它的内容如下:
if(...) exit(); // 通过某个开关来关闭执行
// ...
// 执行某些程序
// ...
sleep($loop); // 这个$loop在include('do.php');之前赋值
include(dirname(__FILE__).'/do.php');
其实通过这种方法执行和while的思路也像。而且同样用到sleep,效率低。
PHP定时任务是一个非常有意思的东西,虽然说实话,用系统的php.exe去直接执行php文件的效率更高,但是对于很多普通站长而言,虚拟主机是无法做到直接php执行原生程序的。本文仅提供一些解决的思路,我也仅仅是在学习中,有很多问题或表述都不正确,希望你指出来;你可以通过本文的思路,开发出自己的一种解决方案,希望你能将方案发布,并与我一起探讨。
-
PHP 多进程任务自动分配 采集 函数 使用备忘 6 进程 5个小时 处理 21 万有效产品 数据测试
2020-12-20 02:31:30客户端示例客户端使用的 是php 写的交互式客户端 可以看到任务分配的非常平均 6 进程 每个进程分配3.4748 万个任务 平均9/S 9个任务每秒任务是远程下载国外亚马逊的图片使用方法 以及函数说明/*** WeiCot Sp ... -
wookteam:WookTeam是一种轻量级的在线团队协作工具,提供各种文档工具,在线思维...任务分配,合并管理等工具
2021-03-18 12:52:50wookteam是一种轻量级的在线团队协作工具,提供各种文档工具,在线思维导图,在线流程图,项目管理,任务分配,关联管理等工具。 wookteam支持团队在线聊天沟通,订阅任务动态实时推送。 wookteam全部开源。 官网... -
PHP--简单实现多个定时调度任务配置
2019-03-13 21:34:27最近回顾 近期在开发一个新项目时,多个过程需要与第三方平台交互,由于其回调是众所周知的不可靠,在接收回调的同时,需要主动查询结果。...如果是较为关键的业务,crontab专门设置一行用于PHP命令行运行或HT... -
hdu 4864 任务分配贪心
2014-10-22 00:38:51http://acm.hdu.edu.cn/showproblem.php?pid=4864 #include #include #include #include #include #include #include #include using namespace std; #define RD(x) scanf("%d",&x) #define RD2 -
分布式定时任务调度框架选型
2021-08-16 00:25:38背景业务场景定期执行任务:如每天0点做资源稽查;需求和痛点集群部署服务时,如何确保任务不被重复执行?---最急迫如何监控、告警等;高可用、无单点故障;优秀的并行处理能力、分片能力;自研 o... -
分布式定时任务开源方案
2022-03-25 23:35:29整理了常用的几种分布式定时任务开源方案的优缺点对比。 -
谈计算(cpu)密集型和io密集型与php性能优化
2021-04-17 21:25:24多年来,php超高的开发效率、低成本的投入、灵活便捷、简单易学、短平快的开发周期,一直为人们所喜欢,也是php能走到今天作为大众主流语言的原因,可是高并发一直是php短板,尤其是在近些年来语言局势逐渐稳定,... -
[php]php内存管理
2018-09-26 19:12:081.内存分配器设计思路 第三章 内存池 第四章 切入主题——PHP内存管理 1.PHP内存管理器数据模型 2.PHP small内存分配方案 3.large内存分配: 4.huge内存分配: 5.内存释放 6.zend_mm_heap和zend_mm_ch... -
计划任务文件锁
2019-11-25 10:39:00使用计划任务执行收益分配等需要修改状态的操作,当网站并发量较大导致程序或者数据库阻塞,以至于当前任务未完成时,第二个任务已经开始运行。此时前一个任务从数据库读取到的待执行数据的状态可能还没有改变,两个... -
GlusterFS场景优化之文件预分配
2019-06-21 15:10:48TaoCloud团队原创:http://www.taocloudx.com/index.php?a=shows&catid=4&id=113 随着新技术的持续发展,全球数据量将继续高速增长,据分析机构预测,中国数据量增长最为迅速,预计到2025年将增加到48.6ZB... -
php+crontab+shell方案实现的秒级定时发起异步请求回调方案
2017-11-15 17:26:57方案介绍方案架构图mysql的任务队列表方案实现源码 redis同步到mysql定时执行任务的的入口实际处理业务(发起通知请求)定时消费方 借助crontab+shell外力实现秒级执行 读取redis任务队列到mysql存储处理秒级... -
请教torque该如何设置队列或是任务或是用户优先级?以及调用哪些node - 计算模拟 - 小木虫 - 学术 科研 ...
2021-05-19 19:53:07我使用的Torque+Maui,但是对于你的第二个问题:队列和节点的映射问题,可以提供一个思路。具体可以参见:http://muchong.com/bbs/viewthread.php?tid=4065399&fpage=1,估计你看过,可能被开头的Torque+Maui吓... -
php 表单自动生成
2021-04-21 08:47:10但是需要一个个去修改,修改列表字段,修改添加、编辑表单,重复工作要做好多次,有什么好的思路去做代码复用了?参考大家的意见我做了如下的实现,请大家看一下谢谢:1.先在行为中生成每个表的配置文件$tables=M()-&... -
定时任务调度与管理平台JobCenter | crontab替代者
2020-12-09 02:58:06窝窝的大多数定时任务其实调用的是本地或远端 Java/PHP/Python Web Service。如果没有一个统一的调度和报警,在集群环境下,我们会:不知道哪一个定时任务执行失败或超时,不见得能第一时间知道——直到最终用户投诉... -
php数组for循环
2021-03-23 23:04:22Swift中的循环语句循环语句能够使程序代码重复执行。Swift编程语言支持4种循环构造类型:while、do while、for和for in。for和while循环是在执行循环体之前...文章关东升2014-09-091211浏览量PHP数组简介v一.PHP数组... -
PHP面试题2021和2022面试、跳槽必备大全!
2021-07-19 14:31:06一、php面试前言 每个Phper在应聘的时候,都会有php面试与笔试。除了口语表达能力之外,还有一点就是实力,这也是你的php面试题所要体现的!那么提前掌握最新的PHP面试题,必然能使你在求职过程中事半功倍! 以下... -
laravelProject:为了更好地了解编写后端应用程序而进行的学校作业
2021-04-13 02:53:59否则,您的项目将不会获得批准,您将获得额外的任务。 -安装[Clockwork]( )扩展,以便在您的计算机中查找[N + 1问题]( )之类的问题Laravel应用程序。 -哦,顺便说一句,您不能使用任何花哨JavaScript框架,**这... -
php面试题(附带答案)
2021-03-05 09:36:30进程是操作系统进行资源分配的单位。 在 Windows 下,进程又被细化为线程,也就是一个进程下有多个能独立运行的更小的单位(线程)。 26、cgi(每次请求结束会退出效率低下) 与fastcgi(开始启动添加进程不会不退出... -
【开发经验】分布式任务调度——xxl-job
2020-06-17 23:17:49 quartz分布式任务调度是通过数据库锁实现的,实现思路简单,但是功能也简单,好多东西都需要自己二次开发。重点是需要简单的二次开发,而且没有可视化。 xxl-job上手很容器,有非常友好的可视化页面,功能... -
高性能服务器架构思路【不仅是思路】
2016-10-31 09:55:19然而,服务器端程序在性能问题上应该有何种基本思路,这个却很少被这些项目的文档提及。本文正式希望介绍服务器端解决性能问题的基本策略和经典实践,并分为几个部分来说明: 1. 缓存策略的概念和实例 2.缓存策略... -
超硬核十万字!全网最全 数据结构 代码,随便秒杀老师/面试官,我说的
2021-04-11 01:11:23} 静态:长度固定 动态:不够存放可以加空间(搬家) /* 子任务名任务:1_2 动态顺序存储线性表的基本实现 */ #include #include #include #define LIST_INIT_SIZE 100 #define LISTINCREMENT 10 #define Status int... -
2020最新PHP面试题(附带答案)
2020-03-02 16:04:59char是固定长度的字符类型,分配多少空间,就占用多长空间。 Varchar是可变长度的字符类型,内容有多大就占用多大的空间,能有效节省空间。 由于varchar类型是可变的,所以在数据长度改变的时,服务器要进行额外的... -
【STM32H7】第9章 ThreadX任务管理
2021-04-20 16:03:06论坛原始地址(持续更新):http://www.armbbs.cn/forum.php?mod=viewthread&tid=99514 第9章 ThreadX任务管理 对于初学者,特别是对于没有RTOS基础的同学来说,了解ThreadX的任务管理非常重要,了解任务管理... -
Swoft 定时任务
2019-06-21 17:28:40Swoft的任务功能是基于Swoole的Task机制,Swoft的Task机制本质上是对SwooleTask机制的封装和加强,Swoft提供了精度为秒的定时任务功能用于替代Linux的Crontab。 Crontab是指需要定期运行的命令列表,以及用于管理该... -
php面试题-2021-php高级篇
2021-03-24 16:03:12PHP代码执行原理 1.源码通过词法分析得到Token。 2.基于语法分析器生成AST抽象语法树 3.抽象语法树转换为opcodes,php解释执行opcodes 1、词法分析器将php代码转换为有意义的标识Token,词法分析器底层使用Re2c实现...