0
$\begingroup$

I am playing around with swarm robotics and trying to figure out a way to simulate it. Here is my dilemma:

I am trying to simulate thousands of agents that will asynchronously communicate with local neighbors to determine an action so a global behavior can be achieved without a centralized logic center. The initial solution to simulate this seems pretty straightforward - each agent is a thread, however, I can't spawn thousands of threads. I also looked into the actor-model framework, but that also does not work since it's single-threaded so I lose the ability for it to be async and whenever an agent is waiting for a signal, it will be thread blocking so other agents will never be able to execute and logic. Any direction will help. Happy to add any clarification. Below is an example of threading. I am trying to create a swarm of 20,000 agents however I cannot create 20,000 threads. I need each agent to run in parallel as that is how it would work with real hardware.

main.py

n = 20000
for i in range(n):
    agent = Agent()
    agent.start()

# Additional logic to start sending and receiving messages between agents.

agent.py

class Agent(Thread):
    def __init__(self):
        ...

    def send_message_to_neighbor(self):
        pass

    def receive_message(self, message):
        pass

error

error: can't start new thread
$\endgroup$
2
  • $\begingroup$ Can you print i inside of your for loop so we can see when your code fails? My best guess is your system has some limit on the number of child processes that can be spawned via a single parent process. $\endgroup$ May 2, 2022 at 21:29
  • $\begingroup$ @domo_arigato it fails when trying to start the 100ish thread. That is the current dilemma, treating each agent as a thread is unfeasible hence the question. Trying to find another approach to be able to simulate 1000's agents $\endgroup$
    – joethemow
    May 3, 2022 at 22:46

1 Answer 1

2
$\begingroup$

This is an ideal use case for async/await.

Your simulated agents will spend nearly all their time waiting for something. It doesn't take a whole thread, with its stack size and address space used and all that, just to wait. Using the async formalism, a small number of threads can service a large number of async agents. At any moment, only a small number of agents will have something to do, and once they do it they will go back to waiting.

A lower-tech, lower-elegance alternative is to frequently poll each agent, giving it a chance to discover whether it has anything to do yet. In this arrangement, you need to explicitly code the agent to return to the caller ASAP so it can get on with polling the next. This also means that any state it needs to preserve from one poll to the next -- even tiny things like loop counters -- must be stored in some instance.

With async/await, the system automagically takes care of that for you. Unfortunately, in my experience, it also leaves you on your own to wrap your mind around this kind of concurrency.

As an aside: in your simulation, even if you use a polling loop, try to manage simulated time abstractly, separated from real time (but with a way to tie them together). This can radically speed up rerunning flocking algorithms, for instance.

$\endgroup$
5
  • $\begingroup$ Won't async/await block the main application thread? $\endgroup$
    – joethemow
    May 3, 2022 at 21:59
  • $\begingroup$ Well, some thread needs to run the async event loop. Just like a GUI program needs some loop to handle mouse and keyboard events, and whatever other work you would put into the main thread. If threads are scarce, or thread hopping is constrained, the challenge is to field both kinds of events when only one loop is "in charge". Typically the APIs have a way to drain all pending events of one kind but without waiting for more. You would run that once each pass of the other kind of loop. $\endgroup$
    – r-bryan
    May 4, 2022 at 14:00
  • $\begingroup$ I put a proof of concept in github.com/rbryan13/swarmbots $\endgroup$
    – r-bryan
    May 4, 2022 at 20:59
  • $\begingroup$ Thanks @r-bryan, this is really helpful. I definitely have a few follow-up questions. I'm still trying to understand asyncio in terms of thread blocking. I am coming from javascript and trying to relate it to async/await. In JS async/await will block the main thread. Looking at the repo on line 155 when you call asyncio sleep, wouldn't that prevent other Robot class instances from calling their update method? $\endgroup$
    – joethemow
    May 5, 2022 at 1:01
  • $\begingroup$ I think extended follow-on discussion is discouraged in answer comments like this one. But that's what the chat thing is for. I made a room at chat.stackexchange.com/rooms/136064/async-robot-swarm-sim and pre-populated it with some remarks. You can ask more there, even if we're not in the room at the same time. BTW, the green check mark on the answer is always appreciated. $\endgroup$
    – r-bryan
    May 5, 2022 at 2:29

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.