I wrote a draft code below. It can be run successfully.
import torch

args.distributed_word_size=2  # each model distributed training on two GPUs
mp = torch.multiprocessing.get_context('spawn')
args.distributed_init_method_run_0 = 'tcp://localhost:00000'  # Local address for model-0
args.distributed_init_method_run_1 = 'tcp://localhost:11111'  # Local address for mode-1

procs = []
for i in range(args.distributed_word_size):    
    # assign two processes and GPUs for model-0
    args.distributed_rank = i
    args.device_id = i
    procs.append(mp.Process(target=run_0, args=(args, ), daemon=True))
    procs[i].start()

for i in range(args.distributed_word_size): 
    # assign two processes and GPUs for model-1
    args.distributed_rank = i
    args.device_id = i + args.distributed_word_size
    procs.append(mp.Process(target=run_1, args=(args, ), daemon=True))
    procs[i+args.distributed_word_size].start()

for p in procs:
    p.joint()

def run_0(args):   
    # TCP initialization for model-0
    torch.distributed.init_process_group(
            backend=args.distributed_backend,
            init_method=args.distributed_init_method_run_0,
            world_size=args.distributed_world_size,
            rank=args.distributed_rank)
    main_0(args)
    ....

def run_1(args):
    # TCP initialization for model-1
    torch.distributed.init_process_group(
            backend=args.distributed_backend,
            init_method=args.distributed_init_method_run_1,
            world_size=args.distributed_world_size,
            rank=args.distributed_rank)
    main_1(args)
    ....