// f_parallel_for // begin - start of range to process // end - 1 after end of range to process // func - worker function of the form worker($begin, $end, $inputdata) - returns an array of max length ($end-$begin) // blocksize - optional blocksize, refer to TBB documentation // Returns: array of maximum length ($end-$begin) // // Call 'func' for non-overlapping array segments to cover all of arraydata // This will use threads as appropriate for the machine. // If a result is returned by 'func' it will be placed into the result array elements corresponding to the input elements Variant f_parallel_for_array(CVarRef arraydata, CVarRef func, int64 blocksize /* = -1 */) { if(!arraydata.isArray()) { raise_error("parallel_for_array expected an array in first argument"); return Variant(); } // Get the input array const Array aArray = arraydata.asCArrRef(); ArrayData *pdArray = aArray.getArrayData(); size_t asize = pdArray->size(); if(asize==0) return Variant(); MemoryManager *mm = MemoryManager::TheMemoryManager().get(); if (RuntimeOption::CheckMemory) { mm->checkMemory(false); } TbbContext myContext = TbbContext::Entry("parallel_for_array"); std::vector<Variant> outArray; outArray.resize(asize); // Construct task parameters PforTaskParameters tclass = PforTaskParameters(myContext, pdArray, func, &outArray); TbbInitializeIfNeeded(); if (blocksize == -1) { // Use auto_partitioner for block size tbb::parallel_for(tbb::blocked_range<int64>(0, asize), tclass, tbb::auto_partitioner()); } else { // Use manually set block size tbb::parallel_for(tbb::blocked_range<int64>(0, asize, blocksize), tclass); } myContext.Exit(); // Create the result array Array resPHPArray = Array::Create(); for(size_t ai=0; ai<outArray.size(); ai++) { Variant amem = outArray[ai]; // printf(" ai=%d, append %s\n", (int)ai, amem.toString().c_str()); if(!amem.isNull()) resPHPArray.append(amem); } if(resPHPArray.size()==0) return Variant(); // i.e null return resPHPArray.getArrayData(); }