A method, comprising: generating a graph for a program, the graph including a plurality of nodes and edges, wherein each node of the graph represents an operation and edges between the nodes represent streams of data input to and output from the operations represented by the nodes; determining, with one or more processors, where in a distributed architecture to execute the operations represented by the nodes, the determining comprising: determining which nodes have location restrictions; assigning locations to each node having a location restriction based on the restriction; partitioning the graph into a plurality of subgraphs, the partitioning including assigning locations to nodes without location restrictions in accordance with a first set of constraints, wherein each node within a particular subgraph is assigned to the same location; locally partitioning each subgraph of the plurality of subgraphs, the local partitioning comprising: identifying subgraphs that need to be split, wherein said identifying is based on whether the subgraph contains blocking operations; preparing the identified subgraphs for splitting into multiple further subgraphs, wherein said preparing includes modifying the identified subgraphs by inserting no-ops before and after each blocking operation; and building a merge graph where the identified subgraphs are split such that each operation is in its own subgraph; repeatedly merging two or more of the subgraphs of the merge graph to an extent possible under local constraints, resulting in locally partitioned subgraphs; and executing each of the locally partitioned subgraphs in a respective single thread. generating a graph for a program, the graph including a plurality of nodes and edges, wherein each node of the graph represents an operation and edges between the nodes represent streams of data input to and output from the operations represented by the nodes; determining, with one or more processors, where in a distributed architecture to execute the operations represented by the nodes, the determining comprising: determining which nodes have location restrictions; assigning locations to each node having a location restriction based on the restriction; partitioning the graph into a plurality of subgraphs, the partitioning including assigning locations to nodes without location restrictions in accordance with a first set of constraints, wherein each node within a particular subgraph is assigned to the same location; locally partitioning each subgraph of the plurality of subgraphs, the local partitioning comprising: identifying subgraphs that need to be split, wherein said identifying is based on whether the subgraph contains blocking operations; preparing the identified subgraphs for splitting into multiple further subgraphs, wherein said preparing includes modifying the identified subgraphs by inserting no-ops before and after each blocking operation; and building a merge graph where the identified subgraphs are split such that each operation is in its own subgraph; repeatedly merging two or more of the subgraphs of the merge graph to an extent possible under local constraints, resulting in locally partitioned subgraphs; and executing each of the locally partitioned subgraphs in a respective single thread. determining which nodes have location restrictions; assigning locations to each node having a location restriction based on the restriction; partitioning the graph into a plurality of subgraphs, the partitioning including assigning locations to nodes without location restrictions in accordance with a first set of constraints, wherein each node within a particular subgraph is assigned to the same location; locally partitioning each subgraph of the plurality of subgraphs, the local partitioning comprising: identifying subgraphs that need to be split, wherein said identifying is based on whether the subgraph contains blocking operations; preparing the identified subgraphs for splitting into multiple further subgraphs, wherein said preparing includes modifying the identified subgraphs by inserting no-ops before and after each blocking operation; and building a merge graph where the identified subgraphs are split such that each operation is in its own subgraph; repeatedly merging two or more of the subgraphs of the merge graph to an extent possible under local constraints, resulting in locally partitioned subgraphs; and executing each of the locally partitioned subgraphs in a respective single thread. identifying subgraphs that need to be split, wherein said identifying is based on whether the subgraph contains blocking operations; preparing the identified subgraphs for splitting into multiple further subgraphs, wherein said preparing includes modifying the identified subgraphs by inserting no-ops before and after each blocking operation; and building a merge graph where the identified subgraphs are split such that each operation is in its own subgraph; repeatedly merging two or more of the subgraphs of the merge graph to an extent possible under local constraints, resulting in locally partitioned subgraphs; and executing each of the locally partitioned subgraphs in a respective single thread.