def execute_multiple(self, actions, immediate=True):
<EOL>split_actions = []<EOL>exceptions = []<EOL>for a in actions:<EOL><INDENT>if len(a.commands) == <NUM_LIT:0>:<EOL><INDENT>if self.logger: self.logger.warning("<STR_LIT>", a.frame)<EOL><DEDENT>try:<EOL><INDENT>if a.maybe_split_groups(self.throttle_groups):<EOL><INDENT>if self.logger: self.logger.debug(<EOL>"<STR_LIT>",<EOL>a.frame, self.throttle_groups)<EOL><DEDENT><DEDENT>except AttributeError:<EOL><INDENT>pass<EOL><DEDENT>if len(a.commands) > self.throttle_commands:<EOL><INDENT>if self.logger: self.logger.debug("<STR_LIT>",<EOL>a.frame, self.throttle_commands)<EOL>split_actions += a.split(self.throttle_commands)<EOL><DEDENT>else:<EOL><INDENT>split_actions.append(a)<EOL><DEDENT><DEDENT>actions = self.action_queue + split_actions<EOL>sent = completed = <NUM_LIT:0><EOL>batch_size = self.throttle_actions<EOL>min_size = <NUM_LIT:1> if immediate else batch_size<EOL>while len(actions) >= min_size:<EOL><INDENT>batch, actions = actions[<NUM_LIT:0>:batch_size], actions[batch_size:]<EOL>if self.logger: self.logger.debug("<STR_LIT>", len(batch), len(actions))<EOL>sent += len(batch)<EOL>try:<EOL><INDENT>completed += self._execute_batch(batch)<EOL><DEDENT>except Exception as e:<EOL><INDENT>exceptions.append(e)<EOL><DEDENT><DEDENT>self.action_queue = actions<EOL>self.local_status["<STR_LIT>"] = queued = len(actions)<EOL>self.local_status["<STR_LIT>"] += sent<EOL>self.local_status["<STR_LIT>"] += completed<EOL>if exceptions:<EOL><INDENT>raise BatchError(exceptions, queued, sent, completed)<EOL><DEDENT>return queued, sent, completed<EOL>
Execute multiple Actions (each containing commands on a single object).
Normally, the actions are sent for execution immediately (possibly preceded
by earlier queued commands), but if you are going for maximum efficiency
you can set immeediate=False which will cause the connection to wait
and batch as many actions as allowed in each server call.

Since any command can fill the current batch, one or more of your commands may be submitted
even if you don't specify the immediate flag.  So don't think of this call as always
being a queue call when immedidate=False.

Returns the number of actions left in the queue, that got sent, and that executed successfully.

NOTE: This is where we throttle the number of commands per action.  So the number
of actions we were given may not be the same as the number we queue or send to the server.

NOTE: If the server gives us a response we don't understand, we note that and continue
processing as usual.  Then, at the end of the batch, we throw in order to warn the client
that we had a problem understanding the server.

:param actions: the list of Action objects to be executed
:param immediate: whether to immediately send them to the server
:return: tuple: the number of actions in the queue, that got sent, and that executed successfully.