当我使用线程时,无法使用xlsxwriter进行编写

我正在尝试使用Python中的xlswriter包编写位置的地址到我的Excel表单中。 我面临的问题是,当我尝试使用线程运行函数的值不写入工作表。 看下面的代码:这里行包含所有原始地址的列表。

import threading import xlsxwriter from geopy.geocoders import Nominatim geolocator = Nominatim() outputLocation = 'output.xlsx' workbook = xlsxwriter.Workbook(outputLocation) w_sheet4 = workbook.add_worksheet('openstreet') def openstreet(): p = 1 for row in rows: #rows consists of raw addresses try: rawAddress = str(" ".join(row[1].strip().split())) #here I am normalizing the addresses using openstreet api location = geolocator.geocode(rawAddress) w_sheet4.write(p, 1, rawAddress) w_sheet4.write(p, 2, str(location.address)) except Exception as e: print "OpenStreet", e p += 1 t4 = threading.Thread(target=openstreet) t4.start() 

如果我不使用线程并通过调用它来运行函数,我可以写入工作表。 看下面的代码:

 import threading import xlsxwriter from geopy.geocoders import Nominatim geolocator = Nominatim() outputLocation = 'output.xlsx' workbook = xlsxwriter.Workbook(outputLocation) w_sheet4 = workbook.add_worksheet('openstreet') def openstreet(): p = 1 for row in rows: #rows consists of raw addresses try: rawAddress = str(" ".join(row[1].strip().split())) #here I am normalizing the addresses using openstreet api location = geolocator.geocode(rawAddress) w_sheet4.write(p, 1, rawAddress) #raw address w_sheet4.write(p, 2, str(location.address)) #normalize address except Exception as e: print "OpenStreet", e p += 1 #t4 = threading.Thread(target=openstreet) #t4.start() openstreet() 

我使用线程的原因,因为我正在使用多个API(谷歌,雅虎,openstreetmap API,bing)试图规范化地址和比较它们。 任何人都可以帮助我,当我使用线程,而不是正常的函数调用时,我不能写入工作表。

谨慎使用! XlsxWriter不是线程安全的。 我发现如果使用in_memory选项,它将使用SharedStrings,并最终写入意外的单元格。 我已经创build了一个票atm:

Github的讨论

从XlsxWriter作者更新:

SharedStrings_get_shared_string_index()方法不是线程安全的。 该类中的其他方法应该是因为它们只从Workbook (每个xlsxwriter对象应该只有一个唯一实例)或通过Workbook析构函数(当工作表线程应该被连接并且活动停止时)被调用。

我发现,如果我使用in_memory选项XlsxWriter将使用SharedStrings

无论您是否使用in_memory,都可以调用SharedStrings类。 in_memory选项涉及使用临时文件而不是SharedStrings(请参阅文档)。

如果你想避免使用SharedStrings,从而避免locking,你可以使用constant_memory模式。 但是有一些注意事项:数据需要按行列写入,不能使用add_table()或merge_range()。 查看构造器文档(上面的链接)以及使用内存和性能。

XlsxWriter还有什么我需要担心的吗?

可能,但没有想到的东西。

我已经解决了它使用threading.join()在函数的结尾。 为什么我们需要使用join()可以从这个链接中理解。 下面的代码正在为我工​​作。

 import threading import xlsxwriter from geopy.geocoders import Nominatim geolocator = Nominatim() outputLocation = 'output.xlsx' workbook = xlsxwriter.Workbook(outputLocation) w_sheet4 = workbook.add_worksheet('openstreet') def openstreet(): p = 1 for row in rows: #rows consists of raw addresses try: rawAddress = str(" ".join(row[1].strip().split())) #here I am normalizing the addresses using openstreet api location = geolocator.geocode(rawAddress) w_sheet4.write(p, 1, rawAddress) w_sheet4.write(p, 2, str(location.address)) except Exception as e: print "OpenStreet", e p += 1 t4 = threading.Thread(target=openstreet) t4.start() t4.join() #we need to use threading.join to make sure the thread function finishes before the main program exits