I'm using a clustered redis. All I want to do is adding a new value to a limited set.
This is my code:
$redis->watch(keyMem)
$count = $redis->scard($keyMem);
if($count < $limit)
$redis->multi()
->sadd($keyMem, $value)
->exec();
and I get:
"cannot use 'watch' over clusters of connections."
I couldn't find any solution and i coded my own lock.
$keyLock = $keyMem."lock";
$start_time = microtime();
while(true){
if($redis->setnx($keyLock, "1")){
$count = $redis->scard($keyMem);
if(i$count < $limit){
$r = $tredis->sadd($keyMem, $value);
}
$redis->del($keyLock);
}
else{
if(microtime() - $start_time > 0.05){
$tredis->del($keyLock);
}
}
}
Related
I have following PHP script which I call via CLI:
#!/usr/bin/php
<?php
$max_stellen = 10;
for ($base=2; $base<=62; $base++) {
for ($power=2; $power<=10; $power++) {
$result = array();
$max_base = gmp_pow($base, $max_stellen);
$x = gmp_init(0);
while ((gmp_cmp($x, $max_base) == -1)) {
$val = gmp_strval($x, $base);
$i = strlen($val);
$left = gmp_pow($x, $power);
$right = gmp_pow($base, $i);
$mod = gmp_mod($left, $right);
if (gmp_cmp($mod, $x) == 0) {
$result[] = $val;
}
unset($left);
unset($right);
unset($mod);
$x = gmp_add($x, 1); // !!! line 30
}
unset($x);
unset($max_base);
$res2 = array();
foreach ($result as &$r) {
$root = substr($r, -1);
$res2[$root][] = $r;
}
unset($result);
foreach ($res2 as $root => &$r) {
echo "X^${power}_${base}($root) = {".implode(', ', $r)."}\n";
}
unset($res2);
echo "\n";
}
}
After a short time (values base=6, power=9), I get following error message:
PHP Warning: gmp_add(): -2147483648 is not a valid GMP integer resource in ... on line 30
If I manually run the code with base=6, power=9, it works, so the error only happens when the loop is running multiple times.
The error message sounds like there are GMP handles allocated which are not freed when they are not used anymore. So after a short time, the handle is out of integer range. But how do I free GMP handles? I already tried to use unset() everywhere, and functions like gmp_free() or gmp_destroy() do not exist.
Update
Reported issue to PHP, since I believe that it is not an expected behavior: https://bugs.php.net/bug.php?id=69702
My PHP script is running out of memory. I have put memory_get_usage( ) inside the loops and found that it is running out of memory after 6MB.
I would like to clearly explain my script and like to get suggestions from you.
I am not sure, If my script is running out of memory because of problems with code .
So, here is the algorithm for my script:
Read the input json data into an array ( approximatley 200 lines of data)
calculate the sum of the array ($sum)
3 variables $starting, $ending and $compare.( Intialize $compare = $starting)
start with $starting=$vmin , calculate scaling factor, scale the original array and calculate sum of it .That new sum is $ending.
Add 10 to $starting until the diff between $ending and $compare is 50.
repeat all the steps until $vmin reaches $vmax with an increment of $vinc
The above algorithm might look insane, But it finds an optimal solution for supply chain related optimization problem.
I would like you to see if my weak coding capabilities are the reason for the memory outage .If so, Please suggest the changes to my script.
Here is my code
$vmax = 10000;
$vmin = 1000;
$vinc = 2000;
//decode the json data
$fp = fopen("data_save3.json", "r");
$inp=file_get_contents("data_save3.json");
fclose($fp);
$inp=json_decode($inp);
//calculate the array sum
foreach($inp as $i=>$element) {
foreach($element as $j=>$sub_element) {
$sum+= $inp[$i][$j];
}
}
//start at vmin and increment it until vmax
for(;$vmin <=$vmax;) {
$starting=$vmin;
$compare = $starting;
//calculate scaling factor
$scale = $starting/$sum;
//calculate the scaled array
$sum2 = 0;
$inp_info2 = $inp;
$ending = newscale($inp_info2,$scale,$sum2);
$optimal = getClosest($starting,$ending,$compare,$sum);
echo $optimal.PHP_EOL;
$vmin = $vmin+$vinc ;
}
// function to find the closest value
$inp_info1=$inp;
function getClosest($starting,$compare,$ending,$sum,$inp) {
global $sum2;
global $compare;
global $inp_info1;
global $starting , $ending, $scale1, $sum, $inp, $inp_info2, $inp_info3,$rowsum2, $rowsum3, $rowsum4, $rowsum5;
if (abs($ending - $compare) < 50){
return $starting;
} else{
$starting = $starting +10;
$scale1 = $starting/$sum;
$inp_info1 = $inp;
$sum2 = 0;
$ending = newscale($inp_info1,$scale1,$sum2);
return getClosest($starting);
}
}
//array scaling function
function newscale($array,$scale,$sum2){
global $sum2,$scale;
foreach($array as $i=>$element) {
foreach($element as $j=>$sub_element) {
$array[$i][$j]*= $scale;
$array[$i][$j] = truncate($array[$i][$j]);
$sum2+=$array[$i][$j];
}
}
return $sum2;
}
//truncate function
function truncate($num, $digits = 0) {
$shift = pow(10, $digits);
return ((floor($num * $shift)) / $shift);
}
i've been dealing with this annoying problem lately which consists of a php script that is supposed to execute quite heavy processing.
This script has a loop that makes comparisons around 25000*25000
i have set maximum time out as 10800
but when i use $time = time(); in the begining of the script
and echo $time - time() at each iteration
script stops after 497 secs
Please help me figure out what could possibly be wrong with the script that i see a blank page after 497 seconds.
Thanks.
EDIT:
while($a<count($data))
{
$AL = (error_get_last());
if($AL['type']==8)
var_dump($AL);
$i=0;
$compdata[$a] = array();
$row = explode("~",$data[$a]);
$dl[$a] = 0;
while($i<count($data))
{
$i += 1;
if(($i-1)==$a)
continue;
$rowc = explode("~",$data[$i-1]);
$j=0;
$cn = 0;
$tw = 0;
$kcv = "";
while($j<$kc)
{
if(Matcher($row[$kcn[$j][0]],$rowc[$kcn[$j][1]],$MCOUNT,$R))
{
$cn += 1;
$tw += $weight[$j];
$kcv .= $kcn[$j][2];
}
$j += 1;
}
if($tw != 0)
{
$compdata[$a][$i-1] = strval($i).$kcv;
$dl[$a] += $tw;
}
}
$compdata[$a] = join(",",$compdata[$a]);
$a += 1;
}
total loop run is about 25000*25000*10
Have you checked in your php.ini execution time
I got the answer fine, but when I run the following code,
$total = 0;
$x = 0;
for ($i = 1;; $i++)
{
$x = fib($i);
if ($x >= 4000000)
break;
else if ($x % 2 == 0)
$total += $x;
print("fib($i) = ");
print($x);
print(", total = $total");
}
function fib($n)
{
if ($n == 0)
return 0;
else if ($n == 1)
return 1;
else
return fib($n-1) + fib($n-2);
}
I get the warning that I have exceeded the maximum execution time of 30 seconds. Could you give me some pointers on how to improve this algorithm, or pointers on the code itself? The problem is presented here, by the way.
Let's say $i equal to 13. Then $x = fib(13)
Now in the next iteration, $i is equal to 14, and $x = fib(14)
Now, in the next iteration, $i = 15, so we must calculate $x. And $x must be equal to fib(15). Now, wat would be the cheapest way to calculate $x?
(I'm trying not to give the answer away, since that would ruin the puzzle)
Try this, add caching in fib
<?
$total = 0;
$x = 0;
for ($i = 1;; $i++) {
$x = fib($i);
if ($x >= 4000000) break;
else if ($x % 2 == 0) $total += $x;
print("fib($i) = ");
print($x);
print(", total = $total\n");
}
function fib($n) {
static $cache = array();
if (isset($cache[$n])) return $cache[$n];
if ($n == 0) return 0;
else if ($n == 1) return 1;
else {
$ret = fib($n-1) + fib($n-2);
$cache[$n] = $ret;
return $ret;
}
}
Time:
real 0m0.049s
user 0m0.027s
sys 0m0.013s
You'd be better served storing the running total and printing it at the end of your algorithm.
You could also streamline your fib($n) function like this:
function fib($n)
{
if($n>1)
return fib($n-1) + fib($n-2);
else
return 0;
}
That would reduce the number of conditions you'd need to go through considerably.
** Edited now that I re-read the question **
If you really want to print as you go, use the output buffer. at the start use:
ob_start();
and after all execution, use
ob_flush();
flush();
also you can increase your timeout with
set_time_limit(300); //the value is seconds... so this is 5 minutes.
First: The problem's name in Wikipedia is "ordered partition of a set".
I have an algorithm which counts possible partitions. To speed it up, I use a cache:
function partition($intervalSize, $pieces) {
// special case of integer partitions: ordered integer partitions
// in Wikipedia it is: ordered partition of a set
global $partition_cache;
// CACHE START
$cacheId = $intervalSize.'-'.$pieces;
if (isset($partition_cache[$cacheId])) { return $partition_cache[$cacheId]; }
// CACHE END
if ($pieces == 1) { return 1; }
else {
$sum = 0;
for ($i = 1; $i < $intervalSize; $i++) {
$sum += partition(($intervalSize-$i), ($pieces-1));
}
$partition_cache[$cacheId] = $sum; // insert into cache
return $sum;
}
}
$result = partition(8, 4);
Furthermore, I have another algorithm which shows a list of these possible partitions. But it doesn't use a cache yet and so it's quite slow:
function showPartitions($prefix, $start, $finish, $numLeft) {
global $partitions;
if ($numLeft == 0 && $start == $finish) { // wenn eine Partition fertig ist dann in Array schreiben
$gruppen = split('\|', $prefix);
$partitions[] = $gruppen;
}
else {
if (strlen($prefix) > 0) { // nicht | an Anfang setzen sondern nur zwischen Gruppen
$prefix .= '|';
}
for ($i = $start + 1; $i <= $finish; $i++) {
$prefix .= chr($i+64);
showPartitions($prefix, $i, $finish, $numLeft - 1);
}
}
}
$result = showPartitions('', 0, 8, 4);
So I have two questions:
1) Is it possible to implement a cache in the second algorithm, too? If yes, could you please help me to do this?
2) Is it possible to write the results of the second algorithm into an structured array instead of a string?
I hope you can help me. Thank you very much in advance!
PS: Thanks for the two functions, simonn and Dan Dyer!
No, I don't think a cache will help you here because you're never actually performing the same calculation twice. Each call to showPartitions() has different parameters and generates a different result.
Yes, of course. You're basically using another level of nested arrays pointing to integers to replace a string of characters separated by pipe characters. (Instead of "A|B|C" you'll have array(array(1), array(2), array(3)).)
Try changing showPartitions() as such:
if ($numLeft == 0 && $start == $finish) { // wenn eine Partition fertig ist dann in Array schreiben
$partitions[] = $prefix;
}
else {
$prefix[] = array();
for ($i = $start + 1; $i <= $finish; $i++) {
$prefix[count($prefix) - 1][] = $i;
showPartitions($prefix, $i, $finish, $numLeft - 1);
}
}
and instead of calling it with an empty string for $prefix, call it with an empty array:
showPartitions(array(), 0, 8, 4);
Off topic: I rewrote the first function to be a little bit faster.
function partition($intervalSize, $pieces) {
// special case of integer partitions: ordered integer partitions
// in Wikipedia it is: ordered partition of a set
// CACHE START
static $partition_cache = array();
if (isset($partition_cache[$intervalSize][$pieces])) {
return $partition_cache[$intervalSize][$pieces];
}
// CACHE END
if ($pieces === 1) {
return 1;
}
if ($intervalSize === 1) {
return 0;
}
$sum = 0;
$subPieces = $pieces - 1;
$i = $intervalSize;
while (--$i) {
$sum += partition($i, $subPieces);
}
$partition_cache[$intervalSize][$pieces] = $sum; // insert into cache
return $sum;
}
Although this is a bit old, nevertheless,
a PHP Class which implements various combinatorics/simulation methods including partitions/permutations/combinations etc.. in an efficient way
https://github.com/foo123/Simulacra/blob/master/Simulacra.php
PS: i am the author