There really shouldn’t be as much difference between the two, both for the time and the accuracy  .
There a mistake in your code however. When testing the accuracy on the test set, you use the model in training mode. You should instead call model.eval() when evaluating only (so that train/eval sensitive layers like batch norm are set to eval mode) and also add with torch.no_grad() in the whole test_accuracy function (so that gradients don’t get computed). When you do that, you also need to call model.train() before training.
I’m not sure how this relates to your time and accuracy problem, particularly regarding the difference between using a loop and a data loader, but it’s the correct way of doing it and it might help  .