Почему записывает много NUL при записи json в многопоточности python

введите сюда описание изображения

введите сюда описание изображения

norm = []
erroe=[]

def threads(func, List, max_workers=20):

futures = []

with ThreadPoolExecutor(max_workers=max_workers) as executor:
    for i in List:
        futures.append(executor.submit(func, i))

    # ждем, когда закончат выполняться задачи
    list_res = []
    for future in futures:
        list_res.append(future.result())

return(list_res)

Используя эту функцию пытаюсь записывать картинки в base64 в json file. Просматривая полученный файл вижу в разных местах много NUL. Хочу понять почему так и как это исправить. При чем копирую этот символ вставляю в код и он просто как один пробел. Предполагаю что это может быть из-за того что несколько потоков пытаются перезаписать один и тот же файл одновременно, хотя тогда бы он наверно вообще не открылся или был бы конфликт.

def read_j(file_name, encod='utf8'):
with open(file_name, 'r', encoding=encod) as f:
    F = json.load(f)
    return F


def write_j(data, file_name, type='w', indent=4, ensure_ascii=False, encod='utf8'):
    with open(file_name, type, encoding=encod) as f:
        json.dump(data, f, indent=indent, ensure_ascii=ensure_ascii)

def url_to_b64(link_to_file, file_name=None):
    # скачивает файл по ссылке и записывает его в виде base64
    fileB64 = base64.b64encode(requests.get(link_to_file).content).decode('utf8')
    if file_name == None:
    return fileB64
else:
    write_f(fileB64, file_name)

    
def func(art):
    start = time.time()
    if art not in downloaded:

        try:
            try:
                page = requests.get('https://сайт' + art + '&locale=ru_RU',
                                timeout=31).content
            except:
                page = requests.get('https://сайт' + art + '&locale=ru_RU',
                                    timeout=25).content

            pics = bs(page, features='html.parser', from_encoding="iso-8859-1").find_all('figure', class_="ds-overview-image")
            if pics != []:
                new_pics = []
                for element in pics:
                    pic = element.find('a').get('href')
                    new_pics.append(pic)
                pics = new_pics
                new_pics = []
            else:
                pics = bs(page, features='html.parser', from_encoding="iso-8859-1").find('div',
                                                             class_='col-xs-12 col-md-4 ds-overview-product-image').find(
                    'a').get('href')
                pics = [pics]

                pics_b64 = []
                for pic in pics:
                    b64_pic = pomo.url_to_b64(pic)
                    pics_b64.append(b64_pic)

            time.sleep(0.1)
            
            d = {art: [pics, pics_b64]}
            norm.append(d)
            # print(pic)
            pomo.write_j(data=norm, file_name='PICS_THIRD.json')
            print(art, "успешный успех")

        except:

            # print(traceback.format_exc())
            error.append(art)
            write_j(error, 'error_of_getting_pics_SECOND.json')
            print(art, "это фиаско брат")

        now_time = time.time() - start
        print('sec', now_time)

threads(func, articls_from_prices, 60)

Ответы (1 шт):

Автор решения: Roman Konoval

Тут можно не заморачиваться со списком norm его синхронизацией и т.д. У вас сама функция парсинга func может возвращать результат и основной поток будет собирать все и записывать:

def func(art):
   ...
   # вместо 
   #  norm.append(d)
   #  pomo.write_j(data=norm, file_name='PICS_THIRD.json')
   # возвращаем результат
   return d

def threads(func, List, max_workers=20):

    futures = []
    with ThreadPoolExecutor(max_workers=max_workers) as executor:
        for i in List:
            futures.append(executor.submit(func, i))

        # ждем, когда закончат выполняться задачи
        list_res = []
        for future in futures:
            list_res.append(future.result())
        # записываем один раз, но можно и после каждого результата в предыдущем цикле
        pomo.write_j(data=list_res, file_name='PICS_THIRD.json')
→ Ссылка