@@ -212,6 +212,7 @@ def download(
212212 ),
213213 remaining_retries = MAX_RETRIES ,
214214 stream = True ,
215+ request_timeout = 3600 ,
215216 )
216217
217218 try :
@@ -522,29 +523,47 @@ def _upload_parts_concurrent(
522523
523524 with ThreadPoolExecutor (max_workers = self .max_concurrent_parts ) as executor :
524525 with tqdm (total = len (parts ), desc = "Uploading parts" , unit = "part" ) as pbar :
525- future_to_part = {}
526-
527526 with open (file , "rb" ) as f :
528- for part_info in parts :
527+ future_to_part = {}
528+ part_index = 0
529+
530+ # Submit initial batch limited by max_concurrent_parts
531+ for i in range (min (self .max_concurrent_parts , len (parts ))):
532+ part_info = parts [part_index ]
529533 f .seek ((part_info ["PartNumber" ] - 1 ) * part_size )
530534 part_data = f .read (part_size )
531535
532536 future = executor .submit (
533537 self ._upload_single_part , part_info , part_data
534538 )
535539 future_to_part [future ] = part_info ["PartNumber" ]
536-
537- # Collect results
538- for future in as_completed (future_to_part ):
539- part_number = future_to_part [future ]
540- try :
541- etag = future .result ()
542- completed_parts .append (
543- {"part_number" : part_number , "etag" : etag }
544- )
545- pbar .update (1 )
546- except Exception as e :
547- raise Exception (f"Failed to upload part { part_number } : { e } " )
540+ part_index += 1
541+
542+ # Process completions and submit new parts (sliding window)
543+ while future_to_part :
544+ done_future = next (as_completed (future_to_part ))
545+ part_number = future_to_part .pop (done_future )
546+
547+ try :
548+ etag = done_future .result ()
549+ completed_parts .append (
550+ {"part_number" : part_number , "etag" : etag }
551+ )
552+ pbar .update (1 )
553+ except Exception as e :
554+ raise Exception (f"Failed to upload part { part_number } : { e } " )
555+
556+ # Submit next part if available
557+ if part_index < len (parts ):
558+ part_info = parts [part_index ]
559+ f .seek ((part_info ["PartNumber" ] - 1 ) * part_size )
560+ part_data = f .read (part_size )
561+
562+ future = executor .submit (
563+ self ._upload_single_part , part_info , part_data
564+ )
565+ future_to_part [future ] = part_info ["PartNumber" ]
566+ part_index += 1
548567
549568 completed_parts .sort (key = lambda x : x ["part_number" ])
550569 return completed_parts
0 commit comments