(
attack, attack_args, num_gpus, first_to_start, lock, in_queue, out_queue
)
| 556 | |
| 557 | |
| 558 | def attack_from_queue( |
| 559 | attack, attack_args, num_gpus, first_to_start, lock, in_queue, out_queue |
| 560 | ): |
| 561 | assert isinstance( |
| 562 | attack, Attack |
| 563 | ), f"`attack` must be of type `Attack`, but got type `{type(attack)}`." |
| 564 | |
| 565 | gpu_id = (torch.multiprocessing.current_process()._identity[0] - 1) % num_gpus |
| 566 | set_env_variables(gpu_id) |
| 567 | textattack.shared.utils.set_seed(attack_args.random_seed) |
| 568 | if torch.multiprocessing.current_process()._identity[0] > 1: |
| 569 | logging.disable() |
| 570 | |
| 571 | attack.cuda_() |
| 572 | |
| 573 | # Simple non-synchronized check to see if it's the first process to reach this point. |
| 574 | # This let us avoid waiting for lock. |
| 575 | if bool(first_to_start.value): |
| 576 | # If it's first process to reach this step, we first try to acquire the lock to update the value. |
| 577 | with lock: |
| 578 | # Because another process could have changed `first_to_start=False` while we wait, we check again. |
| 579 | if bool(first_to_start.value): |
| 580 | first_to_start.value = 0 |
| 581 | if not attack_args.silent: |
| 582 | print(attack, "\n") |
| 583 | |
| 584 | while True: |
| 585 | try: |
| 586 | i, example, ground_truth_output = in_queue.get(timeout=5) |
| 587 | if i == "END" and example == "END" and ground_truth_output == "END": |
| 588 | # End process when sentinel value is received |
| 589 | break |
| 590 | else: |
| 591 | result = attack.attack(example, ground_truth_output) |
| 592 | out_queue.put((i, result)) |
| 593 | except Exception as e: |
| 594 | if isinstance(e, queue.Empty): |
| 595 | continue |
| 596 | else: |
| 597 | out_queue.put((i, (e, traceback.format_exc()))) |
nothing calls this directly
no test coverage detected