Search code examples
pythonfor-looppython-3.3disk-access

How to intentionally slow down a python script so I can have it running forever in the background while I work?


So basically I have a list of 300 values and different averages associated with each one.

I have a for-loop that generates a list of ten of these values at random, and writes it to excel if certain conditions are met based on their averages.

The code runs fine if I loop through 10 million times or less, but that is orders of magnitudes too small. Even if I just double the for loop counter to 20 million my computer becomes unusable while it is running.

I want to iterate the loop 100 million or 1 billion times even. I want it to run slowly in the background, I don't care if it takes 24 hours to get to the results. I just want to use my computer while it's working. Currently, if the for loop goes past 10 million the memory and disk usage of my laptop go to 99%.

Using pyScripter and python 3.3

Comp specs: Intel Core i7 4700HQ (2.40GHz) 8GB Memory 1TB HDD NVIDIA GeForce GTX 850M 2GB GDDR3

Code snippet:

for i in range( 0, cycles ):
    genRandLineups( Red );                     #random team gens
    genRandLineups( Blue );
    genRandLineups( Purple );
    genRandLineups( Green );

    if          sum( teamAve[i] )    <= 600
        and ( ( sum( teamValues[i] ) >  currentHighScore )
            or  sum( teamValues[i] ) >  1024 
            ):
        teamValuesF.append( teamValues[i] )


        sheetw.write( q, 0, str( teamValues[i] ) )
        ts = time.time()
        workbookw.save( "Data_Log.xls" )
        st = datetime.datetime.fromtimestamp( ts ).strftime( '%Y-%m-%d %H:%M:%S' )
        sheetw.write( q, 3, st )
        q = q + 1

        if sum( teamValues[i] ) > currentHighScore:
            currentHighScore = sum( teamValues[i] )

Solution

  • First, I suspect your real problem is that you're just retaining too much memory, causing your computer to run into VM swap, which makes your entire computer slow to a crawl. You should really look into fixing that instead of just trying to make it happen periodically throughout the day instead of constantly.

    In particular, it sounds like you're keeping a list of 10N values around forever. Do you really need to do that?

    If not, start freeing them. (Or don't store them in the first place. One common problem a lot of people have is that they need 1 billion values, but only one at a time, once through a loop, and they're storing them in a list when they could be using an iterator. This is basically the generic version of the familiar readlines() problem.)

    If so, look into some efficient disk-based storage instead of memory, or something more compact like a NumPy array instead of a list.


    But meanwhile, if you want to reduce the priority of a program, the easiest way to do that may be externally. For example, on most platforms besides Windows, you can just launch your script with nice 20 python myscript.py and the OS will give everything else more CPU time than your program.


    But to answer your direct question, if you want to slow down your script from inside, that's pretty easy to do: Just call sleep every so often. This asks the OS to suspend your program and not give you any resources until the specified number of seconds have expired. That may be only approximate rather than absolutely nothing for exactly N seconds, but it's close enough (and as good as you can do).

    For example:

    for i in range(reps):
        do_expensive_work():
        if i % 100 == 99:
            time.sleep(10)
    

    If do_expensive_work takes 18ms, you'll burn CPU for 1.8 seconds then sleep for 10 and repeat. I doubt that's exactly the behavior you want (or that it takes 18ms), but you can tweak the numbers. Or, if the timing is variable, and you want the sleep percentage to be consistent, you can measure times and sleep every N seconds since the last sleep, instead of every N reps.