run - Starts the thread. bgwrite and bgwrite_chunk automatically start the thread.

def run(self):
        '''
            run - Starts the thread. bgwrite and bgwrite_chunk automatically start the thread.
        '''

        # If we are chaining after another process, wait for it to complete.
        #   We use a flag here instead of joining the thread for various reasons
        chainAfter = self.chainAfter
        if chainAfter is not None:
            chainPollTime = self.backgroundIOPriority.chainPollTime
            while chainAfter.finished is False:
                time.sleep(chainPollTime)


        # Pull class data into locals
        fileObj = self.fileObj
        bandwidthPct = self.backgroundIOPriority.bandwidthPct
        bandwidthPctDec = bandwidthPct / 100.0


        # Number of blocks, total
        numBlocks = len(self.remainingData)
        # Bytes written
        dataWritten = 0

        # Mark that we have started writing data
        self.startedWriting = True

        # Create a conditional lambda for flushing. I'd rather just only support flushable streams, but
        #   some unfortunatly just aren't. This should be cheaper than testing with hasattr at each iteration
        if hasattr(fileObj, 'flush'):
            doFlush = lambda obj : obj.flush()
        else:
            doFlush = lambda obj : 1


        # numChunksRateSmoothing - How often we stop for a short bit to be gracious to other running tasks.
        #  float for division below
        numChunksRateSmoothing = float(self.backgroundIOPriority.numChunksRateSmoothing)

        # i will be the counter from 1 to numChunksRateSmoothing, and then reset
        i = 1

        # We start with using max bandwidth until we hit #numChunksRateSmoothing , at which case we recalculate
        #  sleepTime. We sleep after every block written to maintain a desired average throughput based on
        #  bandwidthPct
        sleepTime = 0

        # Before represents the "start" time. When we sleep, we will increment this value
        #  such that [ delta = (after - before) ] only accounts for time we've spent writing,
        #  not in charity.
        before = time.time()

        # timeSlept - Amount of time slept, which must be subtracted from total time spend
        #  to get an accurate picture of throughput.
        timeSlept = 0

        # firstPass - Mark the first pass through, so we can get a rough calculation
        #  of speed from the first write, and recalculate after #numChunksRateSmoothing
        firstPass = True

        if bandwidthPct == 100:
            shouldRecalculate = lambda i, numChunksRateSmoothing, firstPass : False
        else:
            shouldRecalculate = lambda i, numChunksRateSmoothing, firstPass : firstPass or i == numChunksRateSmoothing
            

        while len(self.remainingData) > 0:

            # pop, write, flush
            nextData = self.remainingData.popleft()
            fileObj.write(nextData)
            doFlush(fileObj)
            
            dataWritten += len(nextData)
            if sleepTime:
                sleepBefore = time.time()

                time.sleep(sleepTime)

                sleepAfter = time.time()
                timeSlept += (sleepAfter - sleepBefore)
 
            if shouldRecalculate(i, numChunksRateSmoothing, firstPass) is True:
                # if not sleeptime, we are on first 
                # We've completed a full period, time for charity
                after = time.time()

                delta = after - before - timeSlept

                rate = dataWritten / delta

#                if DEBUG is True:
#                    sys.stdout.write('\t  I have written %d bytes in %3.3f seconds and slept %3.3f sec (%4.5f M/s over %3.3fs)\n' %(dataWritten, delta, timeSlept, (rate) / (1024*1024), delta + timeSlept  ))
#                    sys.stdout.flush()

                # Calculate how much time we should give up on each block to other tasks
                sleepTime = delta * (1.00 - bandwidthPctDec)
                sleepTime /= numChunksRateSmoothing

#                if DEBUG is True:
#                    sys.stdout.write('Calculated new sleepTime to be: %f\n' %(sleepTime,))

                timeSlept = 0
                before = time.time()
                i = 0
#            elif DEBUG is True and i == numChunksRateSmoothing:
#                # When bandwidth pct is 100 (prio=1), the above DEBUG will never be hit.
#                after = time.time()
#
#                delta = after - before - timeSlept
#
#                rate = dataWritten / delta
#
#                sys.stdout.write('\t  I have written %d bytes in %3.3f seconds and slept %3.3f sec (%4.5f M/s over %3.3fs)\n' %(dataWritten, delta, timeSlept, (rate) / (1024*1024), delta + timeSlept  ))
#                sys.stdout.flush()
#
#                timeSlept = 0
#                before = time.time()
#                i = 0

            firstPass = False

            i += 1

        if self.closeWhenFinished is True:
            fileObj.close()

        self.finished = True