Asynchronous transactions should be fine, however if you are doing parallel inserts it is normal/expected for some transactions to abort if they write to the same nodes concurrently. Your async code should thus have some form of retry built into it. Alternatively, if you dont need strong consistency, you could try adding @noconflict directives to all of the predicates involved in this insert.
Also to confirm, when you say you cant use bulk, do you mean you cant use the Dgraph bulk loader, or you cant batch multiple inserts into a single transaction? In my opinion batches are the most effective way to get good insert speed, lots of tiny transactions is going to occur a lot of overhead.