Reputation: 1553
Is openpyxl thread safe? I'm hoping to have one thread changing the worksheet while another thread saves at regular intervals. I was wondering if I needed to add a lock object around the changing and saving operations or whether that is already built in to openpyxl. I did not see anything in the documentation nor any previous questions about threads in openpyxl.
After reading your answer I ran the following test:
import threading
import random
import time
from openpyxl import Workbook
wb = Workbook()
class openpyxlwriting ( threading.Thread):
def run ( self ):
global wb
ws = wb.get_active_sheet()
c = 1
for a in range(100):
for b in range(10000):
ws.cell(column = a,row=b).value = c
c += 1
print "row ",a
class openpyxlsaving ( threading.Thread):
def run ( self ):
global wb
for a in range(1000):
wb.save('test.xlsx')
print "saved"
openpyxlwriting().start()
time.sleep(1)
openpyxlsaving ().start()
which gave me the following trasback: trasback.png
Upvotes: 5
Views: 4244
Reputation: 1553
"OpenPyXl is thread safe; Workbooks can be created concurrently by different threads. However, each workbook should only be modified by one thread at a time."
Form https://bitbucket.org/openpyxl/openpyxl/issues/228/
Upvotes: 5
Reputation: 6571
I decided to see if I could test this, so I created the simple program below that generates a bunch of threads that attempt to read and write the same cell, with random sleeps thrown in.
I didn't see any OS errors that might indicate a problem. On the other hand, I did see some behavior that I didn't quite understand. As the thread count increased, the number of loops completed decreased. So, for example, thread 100 only completed 8 passes through the loop. This might be some sort of an error on my part, or it might indicate an issue with thread safety.
Anyway, this should give you a start in testing it yourself, if you feel so inclined.
import threading
import random
import time
from openpyxl import Workbook
wb = Workbook()
ws = wb.get_active_sheet()
testcell = ws.cell('B9')
counter = 1
class openpyxlworker ( threading.Thread):
def run ( self ):
global wb
global testcell
global counter
for a in range(1000):
time.sleep(random.random()/100)
writing = random.randrange(1, 1000)
testcell.value = writing
time.sleep(random.random()/100)
reading = testcell.value
print "Thread " + str(counter) + " wrote " + str(writing) + " and read " + str(reading)
time.sleep(random.random()/100)
wb.save('test.xlsx')
counter = counter + 1
for b in range(100):
openpyxlworker().start()
Upvotes: 2