You need to make it so that only one thread can write to the file at one time. This is done by having the thread hold a Lock on the file. Once the thread is done with the file, it can release the Lock and it'll get taken by one of the threads waiting for it.
Here's an example of how to use locks, along with a Queue because most often the reason you want to use threads is because you want to perform the same operation on many data objects in parallel.
import threading
import queue
import random
import time
tasks = queue.Queue()
output = open('output.txt', 'w')
output_lock = threading.Lock()
def worker(thread_number):
while not tasks.empty():
task = tasks.get()
# perform long calculation here...
time_to_spend = random.random()
time.sleep(time_to_spend)
result = task * task
# now we have result, want to write it
with output_lock: # this will block until the lock is available
print(thread_number, ': square of', task, 'is', result, '; took', time_to_spend, file=output)
tasks.task_done()
for i in range(100):
tasks.put(i)
for thread in range(8):
threading.Thread(target=worker, args=(thread,)).start()
print('waiting for tasks to complete')
tasks.join()
print('done')
The output I got was:
6 : square of 6 is 36 ; took 0.02233345201885739
7 : square of 7 is 49 ; took 0.0352967148552743
4 : square of 4 is 16 ; took 0.1043699083780637
7 : square of 9 is 81 ; took 0.2158108589024338
1 : square of 1 is 1 ; took 0.3330501408298937
4 : square of 10 is 100 ; took 0.3564233912485101
5 : square of 5 is 25 ; took 0.8496825534757959
0 : square of 0 is 0 ; took 0.8807306770021203
4 : square of 13 is 169 ; took 0.4420943872313102
7 : square of 11 is 121 ; took 0.6772180132068408
5 : square of 14 is 196 ; took 0.1101644871869385
6 : square of 8 is 64 ; took 0.944739067078435
3 : square of 3 is 9 ; took 0.9699315957506418
2 : square of 2 is 4 ; took 0.9903787965119304
3 : square of 20 is 400 ; took 0.029847547355710158
1 : square of 12 is 144 ; took 0.696648284935379
...