Compile and execute source code as a service
By converting imperative source code into functional source code and generating service modules, the problem of difficult performance, scalability and flexibility in traditional software development is solved, and efficient, scalable and flexible software development is achieved.
Patent Information
- Application Number
- CN202080047341.8
- Authority / Receiving Office
- CN · China
- Patent Type
- Patents(China)
- Current Assignee / Owner
- Priority Date
- 2019-06-28
- Filing Date
- 2020-05-12
- Publication Date
- 2025-05-06
- Estimated Expiration
- 2040-05-12
AI Technical Summary
Traditional software development is difficult to achieve performance, scalability and flexibility at the same time, and the imperative programming style leads to complex data dependencies and difficulty in parallelizing and scaling.
By converting the imperative source code into functional source code and compiling it into a service module, using data dependency and invariance points, a partial dependency graph is generated to schedule the execution of service tasks.
It achieves performance improvement, scalability and flexibility, and improves the execution efficiency and scalability of code through parallelization, pre-running and reducing data serialization.
Smart Images

Figure CN114072762B_ABST
Abstract
Description
Background Art
[0001] Ideally, software development results in software with certain characteristics, such as performance, scalability, and flexibility. Performance can often be defined in terms of metrics such as latency and resource utilization. Scalability involves the ability to perform more work by adding new resources, ideally without requiring costly operations such as restarting machines or rewriting underlying code. Flexibility involves the ease with which developers can quickly develop code (e.g., by adding new functionality to existing code). Summary of the invention
[0002] This Summary is provided to introduce a selection of concepts in a simplified form that are further described below in the Detailed Description. This Summary is not intended to identify key features or essential features of the claimed subject matter, nor is it intended to be used to limit the scope of the claimed subject matter.
[0003] The description generally relates to techniques for compiling imperative source code into services and for runtime processing of services. An example includes a method or technique that can be performed on a computing device. The method or technique can include receiving input source code, identifying data dependencies in the input source code, and identifying invariant points in the input source code based at least on the data dependencies. The method or technique can also include converting at least some of the input source code that occurs after the invariant point in the input source code into one or more service modules.
[0004] Another example includes a system having a hardware processing unit and a storage resource storing computer-readable instructions. When the computer-readable instructions are executed by the hardware processing unit, the hardware processing unit may receive input source code for an application, identify data dependencies in the input source code, and identify invariant points in the input source code based at least on the data dependencies. The computer-readable instructions may cause the hardware processing unit to convert at least some of the input source code that appears after the invariant point in the input source code into one or more service modules, and schedule service tasks that execute the service modules at runtime in accordance with the data dependencies.
[0005] Another example includes a method or technique that can be performed on a computing device. The method or technique may include obtaining a partial dependency graph of one or more service modules and service tasks for executing the one or more service modules. The method or technique may also include executing the service tasks in an application process and detecting a specific runtime value output by a specific service task. The method or technique may also include inserting one or more additional service tasks into the partial dependency graph based at least on the specific runtime value to obtain a completed dependency graph. The method or technique may also include executing one or more additional service tasks in the application process based at least on the completed dependency graph.
[0006] The examples listed above are intended to provide a quick reference to assist the reader and are not intended to limit the scope of the concepts described herein. BRIEF DESCRIPTION OF THE DRAWINGS
[0007] The detailed description is described with reference to the accompanying drawings. In the drawings, the left-most digit(s) of a reference number identifies the drawing in which the reference number first appears. The use of similar reference numbers in different instances in the description and the drawings may indicate similar or identical items.
[0008] Figure 1 An example process flow for transforming input source code consistent with some implementations of the present concepts is illustrated.
[0009] Figure 2 , Figure 4 , Figure 6 and Figure 8 An example of inputting source code in a development environment interface consistent with some implementations of the present concepts is illustrated.
[0010] Figure 3 , Figure 5 , Figure 7 and Fig. 9 Examples of transformed source code consistent with some implementations of the present concepts are illustrated.
[0011] Fig.10 An example runtime process flow consistent with some implementations of the present concepts is illustrated.
[0012] Fig.11 Several dependency graphs consistent with some implementations of the present concepts are illustrated.
[0013] Fig.12 Additional source code examples consistent with some implementations of the present concepts are illustrated.
[0014] Fig.13 An example system consistent with some implementations of the present concepts is illustrated.
[0015] Fig.14 and Fig.15 Example methods or techniques consistent with some implementations of the present concepts are illustrated. DETAILED DESCRIPTION
[0016] Overview
[0017] As noted, software development aims to produce software that exhibits good performance, scalability, and flexibility. However, traditionally, software developers have had to choose from programming approaches that tend to favor some of these characteristics at the expense of others. For example, one approach to writing cloud software is to write a "monolith" - a single, large piece of code that runs the entire cloud service in a single process. Cloud monoliths tend to be high-performance and can be easily scaled to increased load by simply adding new processes running copies of the cloud monolith code. However, monolithic code tends to lack flexibility - it is difficult for developers to make changes to the cloud monolith without causing undesired side effects or errors that often slow down the development process.
[0018] Another approach to developing software is the library model, in which developers write individual code modules or "libraries" that can be linked to other modules at compile time (static libraries) or at runtime (dynamic libraries). This approach tends to result in executables that offer good performance and flexibility, but can be difficult to scale when changes are made to individual libraries due to dependencies between libraries. Another alternative is to deploy code modules as independent services that execute in separate processes. This can be a scalable and flexible approach by writing services that lack dependencies on each other, but can exhibit poor performance due to excessive use of the network and serialization of data between processes.
[0019] In addition, today's programmers tend to be familiar with the imperative programming style. In imperative programming, developers manipulate program state (i.e., data) by operating on data, typically using a procedural programming language such as C or FORTRAN or an object-oriented programming language such as Java, C++, and C#. However, imperative programming typically results in code modules that have side effects on external data or that execute differently depending on external program state. Due to these data dependencies, it may be difficult to parallelize imperative code or execute parts of imperative code in an order different from the order originally specified by the developer.
[0020] One approach that helps alleviate some of the problems mentioned above involves functional programming. In functional programming, developers write code that avoids mutable data. As a result, functional code often lacks data dependencies between various code modules, and thus functional code modules can be more easily parallelized or executed independently, for example, by running function modules optimistically. However, writing functional code requires developers to either write in a functional programming language such as LISP that the developer is unfamiliar with, or force themselves to use unfamiliar functional programming techniques using a language originally designed for imperative or object-oriented programming.
[0021] The disclosed implementations are generally intended to provide some of the benefits of functional programming without requiring developers to write functional code. At a high level, the disclosed implementations can transform input source code written in an imperative style into functional code. The functional code can implement the functionality of the input source code in one or more service modules. As discussed more below, converting the input source code into service modules can enable the service modules to execute independently at runtime. As discussed in detail below, this can provide performance improvements via optimistic execution, prioritization, parallelization, and reduced data serialization.
[0022] The disclosed implementation also provides scalability because service modules can be deployed as needed, for example by running additional copies of frequently used services and fewer copies of less frequently used services. Furthermore, the disclosed implementation provides flexibility because service modules can be updated by hot-swapping new code without shutting down the entire application for recompilation and rebooting as is usually done with library-based solutions.
[0023] Example source conversion process flow
[0024] Figure 1 An example code conversion process 100 consistent with the disclosed implementation is illustrated. The code conversion process 100 performs various operations on an input source code 102, which may include a portion or all of an application, as discussed in more detail below. For example, the input source code may be an object-oriented program written in a language such as Java, C++, or C#, with various defined object types and corresponding member functions and variables. In other cases, the input source code may be written in a procedural language such as C or FORTRAN. In either case, there may be many different complex dependencies between the various data items in the input source code.
[0025] Traditionally, developers are responsible for specifying the order of operations in input source code to achieve correct programming results, and the input source code is compiled into binary code or bytecode that performs the operations in the order specified by the programmer. In some implementations, the code conversion process 100 converts the input source code into a functional, service-based code that can be executed in an order different from the order specified by the input source code 102. As discussed more below, one way to describe functional code is that the code can be represented as a directed acyclic graph with immutable outputs.
[0026] The code conversion process flow 100 begins by performing a dependency analysis 104 on the input source code 102. The dependency analysis builds a dependency graph 106 that represents the dependencies between various data items in the input source code. For example, if one variable in the input source code is modified based on the value of another variable, the dependency graph will identify this dependency between the two variables. Depending on the complexity of the application, the dependency graph can be relatively simple or very complex. Example dependency graphs will be referenced below. Fig.11 Have more discussion.
[0027] The code conversion process flow 100 continues with invariant analysis 108. Where possible, the invariant analysis identifies lines in the input source code where various data items become "immutable." In other words, the invariant analysis identifies points in the input source code where certain data items stop being modified. In some cases, a given data item does not become immutable at any point, for example, the data item is susceptible to being changed at any time. In other cases, data items may be immutable throughout the source code, for example, a given data item may be assigned an initial value and then never modified. In more cases, some data items may be modified by one or more operations in the code and then become immutable once a certain processing point is reached. For those data items that do become immutable at some point, the invariant analysis identifies invariant points 110, which represent the corresponding points where those data items become immutable. Example invariant analyses will be referenced below. Fig.12 Have more discussion.
[0028] Once the invariant analysis 108 is completed, the invariant points 110 are input to a code conversion process 112. The code conversion process outputs a modified source code 114, which may include an imperative source code portion 116 and a functional source code portion 118. The imperative source code portion typically includes a portion of the input source code that appears before the identified invariant points for a given data item. In some cases, the imperative source code may also be modified by the code conversion process. However, even if modified, operations are performed on the variable data items in the imperative source code in the order specified in the input source code 102 to ensure correctness.
[0029] The functional source code portion typically includes code that is executed after an invariant point for a given data item. As discussed in more detail below, the functional source code portion may include service modules that perform operations originally specified imperatively in the input source code and may lack data dependencies on other service modules. As a result, the service modules do not necessarily need to perform operations in the same order specified by the input source code 102, as discussed in more detail below.
[0030] Modified source code 114 may be input to bytecode generation process 120. Bytecode generation process may convert imperative source code portion 116 into imperative bytecode 122, and may convert functional source code portion 118 into service bytecode 124. As discussed below, the service bytecode may perform similar or equivalent functions as the input source code from which it was derived, while executing as one or more service tasks that allow for parallelization, pre-running, prioritization, and / or reduced data serialization, as discussed more below.
[0031] For the purposes of this document, the term "imperative source code" means source code that is typically written by a developer and that manipulates program state via operations defined in the source code. Imperative source code often has complex data dependencies between various code modules. The term "functional source code" means imperative source code that has been manipulated by a code conversion process to alleviate at least some of the data dependencies in the imperative source code. In the examples discussed herein, the functional source code is generated by converting certain operations defined in the imperative source code into service modules. The term "imperative bytecode" means bytecode derived by compiling imperative source code. The term "service bytecode" means bytecode derived by compiling functional source code, which includes service modules and corresponding service tasks that can be scheduled and orchestrated at runtime, as discussed further below.
[0032] First source code example
[0033] Figure 2 The development environment interface 200 is illustrated with a code editor 202 that can be used to input source code 204 for subsequent processing by the code conversion process 100. Note that the following examples use C# as source code examples, but the techniques described herein can be easily extended to other programming languages. Figure 2In the example shown in , the input source code includes a class ParallelLoop with a member function named Execute(), which receives an input parameter, a string array named inputs. The Execute function processes each element of the input string using a function named TimeConsumingCalculation(), which outputs a return string that is placed in a local string array named responses. The TimeConsumingCalculation() function is called three times in a for loop, and the return values populate the corresponding entries in responses. When the Execute() function completes, a join operation is performed on each entry in responses, and the results of the join operation are returned to the caller of the Execute() function.
[0034] Traditionally, the input source code 204 will be directly compiled into bytecodes that perform the operations of the Execute() function in sequence, including each iteration of the for loop. Thus, each iteration of the for loop needs to complete execution before the next iteration of the for loop begins. Thus, assuming that the TimeConsumingCalculation() function takes 0.5 seconds each time it is called, the Execute() function will take at least 1.5 seconds. In addition, under normal circumstances, the Execute() function will not run until it is explicitly called by some other module defined in the source code.
[0035] In general, the input source code 204 can be part of a larger application that creates one or more instances of the ParallelLoop class. Each instance of the ParallelLoop class can pass different input strings to the Execute() function. The invariant analysis 108 can detect whether those input strings are mutable, for example, whether they can be changed after the Execute() function is called. For those calls to the Execute() function with mutable inputs, code conversion can compile the input source code into corresponding imperative bytecodes 122. However, for those calls to the Execute() function with immutable inputs, for example, the inputs are not modified in the input source code after the Execute() function is called, those instances of the ParallelLoop class can be converted into functional source code portions 118 and corresponding service bytecodes 124, as shown below.
[0036] Figure 3An example output of the development environment as converted source code 300 is illustrated, which is an example of functional source code. In this example, the input source code 204 has been converted into a class called ConvertedParallelLoop. The functionality of the Execute() function has been decomposed into several functional modules, Plugin_0, Plugin_1, and Workflow. In general, Plugin_0 is a service module that executes the TimeConsumingCalculation() function, Plugin_1 is a service module that aggregates the intermediate results of TimeConsumingCalculation() into the final return value, and the Workflow module coordinates the processing performed by Plugin_0 and Plugin_1.
[0037] Comparing the input source code 204 and the converted source code 300, note the following points. First, the input source code sets forth a specific order in which operations are to be performed on multiple data items, such as the elements of the inputs and responses arrays. Traditionally, the input source code is compiled into bytecodes that implement these operations in the order defined in the source code.
[0038] On the other hand, the converted source code 300 uses multiple service modules such as Plugin_0 and Plugin_1 to implement the functionality of the input source code 204. The workflow module specifies multiple service tasks, which can be used at runtime to execute one or more instances of each service module. In this article, the workflow module has created three service tasks, which can execute different instances of the Plugin_0 service module. Each service module is defined in a manner similar to a microservice, where the corresponding service modules are independently deployable and lack data dependencies on each other. However, as discussed below, the service modules can be executed using multiple tasks that run in a single application process and communicate via shared memory, thereby avoiding the serialization and network overhead typically associated with a microservice architecture that runs services in separate processes and performs inter-service communication on the network.
[0039] Reference Figure 2, note that each iteration of the for loop populates different iteration-specific entries in the responses string returned when the Execute() function completes. As a result, the final value of the local responses variable does not depend on the order in which the loop iterations are executed. The code conversion process 112 can detect that each entry in the responses string is only updated in one iteration of the loop. Each iteration is determined to be independent of any other iteration. Similarly, invariant analysis has determined that each input to the iteration is immutable at the beginning of the iteration. As a result, the functionality of the loop iteration can be converted into parallel tasks. In this way, the workflow service module created by the code conversion process uses asynchronous service tasks to execute three instances of Plugin_0.
[0040] In general, asynchronous tasks can be run at any time and in any order. This allows each service task to run without an explicit call from another code module. Instead, each service task can be run at any time when input data for that service task is available, providing an opportunity to run service tasks in advance. Figure 3 In the example workflow module shown in , the await keyword is used to ensure that a given service task waits for data used as input to the task. Assuming that all three elements of the input are available together at runtime, the workflow module effectively configures these tasks so that they can be parallelized at runtime.
[0041] For the purposes of this document, the term "application process" refers to application code, memory allocated to execute application code, and state associated with an application process. An application process may have one or more threads, each of which may share the same memory allocated to the process. For example, in some cases, an operating system or hypervisor may allocate a specified virtual memory space to an application process, and each thread in an application process may share the virtual memory space. The term "thread" refers to a sequence of instructions that can be independently scheduled at run time.
[0042] The term "task" refers to a data object that represents work that has been performed or is about to be performed by an application. At run time, different tasks can be assigned to different threads. When two or more tasks are executed simultaneously in different threads, the tasks can be considered to be running in parallel. In some cases, different threads can run on different processors, and in other cases, a single processor can execute multiple threads simultaneously. The term "service task" refers to a task that executes a service module.
[0043] Second source code example
[0044] Figure 4Another source code example is illustrated. Here, the code editor 202 of the development environment interface 200 includes an input source code 402. In this case, the input source code includes a class SerialLoop with a member function called Execute(), which receives a string called input as an input parameter and returns a local variable called sofar as an output parameter. In addition, another local variable responses is an array of three strings, which is updated in each loop iteration using the output of the TimeConsumingCalculation() function on the variable sofar. Because sofar is updated in the loop itself and is used as an input to TimeConsumingCalculation() in subsequent loop iterations, each loop iteration has data that depends on the previous iteration.
[0045] As in the previous example, input source code 402 is routinely directly compiled into bytecodes, which perform the operation of the Execute() function in the order defined in the input source code, and wait for the Execute() function to be called elsewhere in the code. However, as in the previous example, the application may include an instance of the SerialLoop class, which receives immutable data as input to the Execute() function. Any call to the Execute() function of the SerialLoop class that occurs after the invariance point of the input parameter in the input source code may be converted as shown below. In particular, the development environment may convert the input source code 402 into a set of discrete service modules, as discussed in more detail below.
[0046] Figure 5The example output of the development environment as the converted source code 500 is illustrated, and the converted source code 500 is another example of the functional source code. In this example, the input source code 402 has been converted into a class called ConvertedSerialLoop with two modules of Plugin_0 and workflow. The workflow module creates three service tasks, and each service task runs Plugin_0 at runtime. Although asynchronous tasks can usually run independently, in this case, the code conversion process 112 has identified the data dependency across multiple loop iterations. The first service task defined in the workflow module runs Plugin_0 and waits for input data, and can run immediately when the input data is available. However, the latter two service tasks depend on response variables response0 and response1, which are available after being output by the first service task running Plugin_0. As a result, the data dependency in the original SerialLoop class is taken into account, and the converted source code can still be correctly run, because the service tasks will run serially rather than in parallel.
[0047] As discussed further below, while this example may not provide an opportunity for parallelization, there is nevertheless an opportunity to run the service tasks ahead of time and / or prioritize the execution of the service tasks of the service module at runtime. Thus, the converted source code 500 may still achieve some performance enhancements that may not be available to the input source code 402, which would typically wait until an explicit call to the Execute() function occurs before performing the aforementioned operations.
[0048] Third source code example
[0049] Figure 6 Another source code example is illustrated. Here, the code editor 202 of the development environment interface 200 includes an input source code 602. The input source code includes a class MixedParallelSerialLoop with a member function called Execute(), which receives a string array called inputs as an input parameter and returns a local variable called combine as an output parameter. In this example, the call to TimeConsumingCalculation() takes different elements of inputs as parameters in each iteration of the loop. Like this, the outputs filled into the responses string array are independent in the loop iteration. In other words, no matter whether the loop iteration is executed in sequence, the responses string array looks the same.
[0050] However, the local string variable combine is updated using the "+=" string concatenation operation. Unlike mathematical addition, string concatenation is not commutative. In other words, string1+string2+string3 is not necessarily equal to string1+string3+string2. Thus, the "+=" operation performed on the combine variable imposes data dependencies between loop iterations. As in the previous example, the input source code 602 is conventionally compiled directly into bytecodes that perform the operations defined in the input source code. Thus, for example, in each iteration of the loop, TimeConsumingCalculation() is first called, followed by the concatenation operation.
[0051] In some cases, an application may include an instance of a MixedParallelSerialLoop class that receives immutable data as an input parameter to an Execute() function. Any call to the Execute() method of the MixedParallelSerialLoop class in the input source code that occurs after an immutability point for the data used as input to Execute() may be converted into a service module. In particular, the development environment may compile the source code into a set of discrete service modules, as discussed in more detail below.
[0052] Figure 7 An example output of the development environment as converted source code 700 is illustrated. In this example, the converted source code includes a class named ConvertedMixedParallelSerialLoop, which includes a Plugin_0 service module, a Plugin_1 service module, and a workflow module. The Plugin_0 service module performs a TimeConsumingCalculation() function on the elements of the input string, and thus once the inputs are filled at runtime, the workflow module can use an asynchronous service task to execute Plugin_0. However, the call to Plugin_1 in the workflow module waits for the results of all instances of Plugin_0 - in other words, before Plugin_1 is invoked, each response variable response0, response1, and response2 is filled by a different task that executes Plugin_0.
[0053] By converting the input source code 602 into the converted source code 700 as discussed above, the three iterations of TimeConsumingCalculation() in the input source code can be partially parallelized, prioritized, and pre-run at runtime without following the order of operations defined in the input source code. The circular dependency in the join operation can be handled by await statements in the workflow module, which wait for local variables to be filled before running Plugin_1.
[0054] so, Figure 6 and Figure 7 An example is illustrated together in which some parts of a loop can be parallelized into service modules that are executed as a set of asynchronous tasks, and other parts of the loop can be implemented by waiting for the results of these service tasks. As a result, while still executing logically correct code that does not violate data dependencies in the input source code 602, some benefits of parallelization are also achieved.
[0055] Notice, Figure 6 and Figure 7 Specific subtleties in the code conversion process 112 are illustrated. In the input source code 602, the TimeConsumingCalculation() call and the += operation occur in the same loop. The code conversion process can move the += operation to run later, for example, as late as possible without changing the behavior of the application. This is illustrated in the converted source code 700 by Plugin_1, which runs after the three calls to TimeConsumingCalculation() in Plugin_0. This allows the calls to TimeConsumingCalculation() to be parallelized.
[0056] Fourth source code example
[0057] Figure 8Another source code example is illustrated. Here, the code editor 202 of the development environment interface 200 includes an input source code 802. In this case, the input source code includes a class named EmbeddedFunctions, which has member functions Execute(), DoPart1(), and DoPart2(). DoPart1() executes a C# function named ToLower(), which converts a string to lower case. DoPart2() executes a TimeConsumingCalculation() function and a C# function named ToUpper(), which converts a string to upper case. The Execute() function calls DoPart1 on a string input parameter named input, passes the result to DoPart2 via a local variable named output0A, and passes the result of DoPart2 to DoPart1 via another local variable named output0B.
[0058] As in the previous example, this source code example will be directly compiled into bytecode routinely.The operation will be performed in the specified order according to the source code, and will not be performed before being called up by another module in the application.Yet, as in the previous example, the application can include some instances of the EmbeddedFunctions class, and these EmbeddedFunctions classes receive immutable data as the input to the Execute () function.Any call to the Execute () function of the EmbeddedFunctions class that occurs after the invariance point for the input parameter in the original source code can be converted as shown below.Especially, as discussed in more detail below, the development environment can convert the input source code 802 into a group of discrete functional service modules.
[0059] Fig. 9The example output of the development environment as the source code 900 after conversion is illustrated.In this example, the source code after conversion includes another class called ConvertedEmbeddedFunctions.The ConvertedEmbeddedFunctions class includes two service modules Plugin_0 and Plugin_1, and workflow module.Plugin_0 converts the input string into lowercase, performs TimeConsumingCalculation() to the result, and then converts the result into uppercase.This has effectively performed the same operation of the first two lines of code in the Execute function with input source code 802.Plugin_1 converts the string input to this service module into lowercase.The workflow module first creates a service task, which runs Plugin_0 and stores the return value in the local response0 variable, and then waits for response0 to be filled by the service task running Plugin_0 before passing it to Plugin_1.
[0060] Note that this particular example does not demonstrate parallel instantiation of plugins. However, as discussed more below, performance advantages may be gained through optimistic execution, prioritization, scheduling, and / or orchestration.
[0061] Example runtime process flow
[0062] Fig.10 An example runtime process flow consistent with disclosed implementations is illustrated 1000. The runtime process flow involves inputting various items into a runtime environment 1002 to obtain a scheduling and / or orchestration output 1004. As discussed further below, the scheduling output may determine when to run a given service task, and the orchestration output may determine where to run a given service task, e.g., in a specific process or on a specific physical machine.
[0063] The input to the runtime environment 1002 may include imperative bytecodes 122 and service bytecodes 124. As noted, the service bytecodes represent the Figure 1 The discussed code conversion process 112 outputs a service module, while the imperative bytecode represents the sequence of operations originally defined in the input source code 102. In general, the runtime environment can coordinate the operation of these two types of bytecodes to obtain the same logical functionality as the input source code. The runtime process can also consider the dependency graph 106 generated during the code conversion process to ensure that the service tasks are executed in a manner consistent with the data dependencies in the dependency graph.
[0064] Runtime environment 1002 can also consider execution log 1006, and execution log 1006 can convey information such as how long the previous instance of each service task has been executed. In addition, the execution log can convey information such as the data distribution of each runtime value. With this information, the runtime environment can identify information such as the critical path, for example, the path that takes the longest time to execute through the dependency graph. The runtime environment can run each service task on the critical path early, and / or by providing a higher scheduler priority for these service tasks to give priority to executing them when threads become available. In addition, when data dependencies allow parallelization, the runtime environment can parallelize execution by running service modules in parallel in different service tasks.
[0065] Given the above inputs, runtime environment 1002 can generate scheduling and / or orchestration output 1004. Typically, scheduling output communicates when a specific service task is executed, and orchestration output communicates where a specific service task is executed, for example, on a specific virtual machine or physical machine. Various scheduling and orchestration considerations are further described below.
[0066] At a high level, the runtime process flow 1000 can be viewed as a mechanism for executing code when data is available, rather than executing code in a predefined order as set forth in the source code. Because at least a portion of the source code has been converted into individual service modules as described above, the service modules can be scheduled to run in corresponding service tasks according to the corresponding workflow modules. The runtime environment 1002 can coordinate runtime communication of data between corresponding service tasks according to the workflow modules, for example, initiating a given service task once input data for the service task becomes available.
[0067] Example dependency graph
[0068] As noted, the code conversion process 100 can generate a dependency graph 106 at compile time. As discussed more below, the runtime environment 1002 can schedule service tasks at runtime based on the dependency graph. In addition, in some cases, the runtime environment can update the dependency graph at runtime using values determined at runtime. For example, the runtime environment can update the dependency graph using the output of the service task and / or the results calculated by executing the imperative bytecode. In some cases, the dependency can be represented as a directed acyclic graph. Typically, if a given code segment can be represented as a directed acyclic graph, this means that the code can be regarded as functional code and can be converted into a service module for parallelization and / or pre-running.
[0069] Fig.11 Three dependency graphs 1110, 1120, and 1130 are illustrated. Dependency graph 1110 generally corresponds to Figure 2 and Figure 3 Node 1110(1) represents the first service task that runs Plugin_0 of the ConvertedParallelLoop class and fills response0. Node 1110(2) represents the second service task that runs Plugin_0 of the ConvertedParallelLoop class and fills response1. Node 1110(3) represents the third service task that runs Plugin_0 of the ConvertedParallelLoop class and fills response3. Node 1110(4) represents the operation performed by Plugin_1 on these three variables. The edges in the figure represent the dependencies between the various service tasks. In this case, the dependency analysis 104 performed on the input source code at compile time can generate a completed dependency graph from the input source code 204, and thus can identify that the three service tasks can run in parallel. Because the completed dependency graph can be generated at compile time, the runtime environment 1002 can also run these service tasks in advance, and / or once the input data is available, for example, from other code modules in the application, they can be prioritized at any time.
[0070] However, in some instances, the compile-time dependency analysis may not be able to fully complete the dependency checking process. For example, consider the example of a loop that has at least 3 iterations without a maximum number of iterations. In some implementations, separate service tasks for the first three iterations can be created at compile time as discussed above. In addition, a partial dependency graph, such as the compile-time dependency graph 1120. Here, the dependency graph 1120 has nodes similar to those of the dependency graph 1110, with an additional node 1120(1). Node 1120(1) represents any additional loop iterations that may occur at runtime and is shown in dashed lines to indicate that these iterations are not resolved at compile time.
[0071] The runtime environment 1002 can receive a dependency graph 1120 from a compiler. At some point, the number of loop iterations may become final, and the runtime environment can identify the point in the code where this occurs, for example, a statement that sets the loop counter is not subsequently modified during execution. For this example, assume that the total number of loop iterations determined at runtime is 5. At this point, the runtime environment can modify the dependency graph 1120 to obtain a completed dependency graph 1130. The completed dependency graph 1130 has two new nodes 1130(1) and 1130(2) that have replaced node 1120(1). Nodes 1130(1) and 1130(2) represent additional service tasks that implement two additional loop iterations. As previously discussed, the runtime environment can cause these two service tasks to run Plugin_0.
[0072] More generally, the runtime environment 1002 can receive data dependencies generated at compile time, for example, in the form of a dependency graph. The dependency graph can identify ordering constraints for executing the various service tasks, and the runtime environment can run the service tasks in any order consistent with the ordering constraints. In some cases, the runtime environment can run any imperative bytecode that has not yet been converted into a service to obtain result data, and the result data can be provided to the various service modules as input data when it becomes available. At this point, the imperative bytecode no longer defines the order in which operations are performed, and instead, the runtime environment can arrange the various service tasks in any manner, provided that the ordering constraints determined at compile time and / or completed at runtime are complied with.
[0073] As noted, when a partial dependency graph is generated at compile time, runtime environment 1002 can complete the partial dependency graph at runtime based on specific runtime values provided by a given service module. Once the dependency graph is completed, the runtime can insert additional service tasks into the application process, for example, as represented by nodes 1130(1) and 1130(2) in dependency graph 1130. Note that in some cases, the completed dependency graph can be represented as a directed acyclic graph with directed edges that represent the direction of any data dependencies in the graph.
[0074] Immutability Code Example
[0075] As noted, a given application may include source code that performs operations on data items in a specified order. In some cases, the results of those operations will depend on mutable data, where the operations can be performed in a specified order according to the source code to ensure the correct results. However, in other cases, the results of those operations may depend on immutable data, that is, data that has a fixed value at compile time or at some point in runtime. Once a given data item is made immutable, the operations on that data item can be converted into functional code using the techniques described above. The following is a source code example that illustrates the difference between mutable and immutable data.
[0076] Fig.12 The source code snippet 1200 having a variable named pl is shown. The source code snippet 1200 is a reference to the above-mentioned Figure 2 1200 , an instance of the ParallelLoop class in question. The Execute() routine of the ParallelLoop class is called twice in code snippet 1200, once in a function named Main1() and another time in a function named Main2(). The call to Execute() in Main1() uses a local string variable named in1, which is initialized to "abc" and then passed as an input to Execute(). In this example, in1 is immutable because in1 is not modified after the call to Execute(). This is so because the scope of in1 is local to Main1(), and therefore in1 is not modified outside of the illustrated snippet. On the other hand, the call to Execute() in Main2() uses a local string variable in2, which is modified after the call to Execute(). As a result, in2 is not immutable. During the code conversion process, the first call to Execute() in Main1() can be converted into a parallelized service, as described above with reference to Figure 3 As discussed above, the second call to Execute() in Main(2) can remain as Figure 2 as shown in .
[0077] In some cases, invariant analysis can be relatively complex, depending on the structure of the source code being analyzed. For example, the values of certain variables may depend on function calls in the code, and these functions may call other functions. In some implementations, invariant analysis can involve recursively evaluating function calls in the code until a given data item is confirmed to be immutable and / or a stopping condition is reached. For example, some implementations can specify the stopping condition as a threshold number of recursive evaluation layers. Once the threshold number is reached, the invariant analysis can stop and designate the data item in question as mutable. While this may preclude some of the performance benefits discussed in this article, it ensures correct code execution.
[0078] The problem in question involves function calls that pass parameters by value, as opposed to by reference. Variables passed to a function by reference can be modified within the function body. On the other hand, when a variable is passed to a function by value, the called function receives a copy of the variable as an input parameter and cannot modify the variable itself. As a result, function inputs passed by value are immutable, and even in instances where variables passed as input parameters are mutable, only functions that pass parameters by value can run in parallel.
[0079] Scheduling and Orchestration Considerations
[0080] As mentioned previously, the input source code examples discussed in this article are routinely compiled into bytecodes that perform the operations in the source code in the specific order defined by the source code. As a result, each function defined in the source code is executed when explicitly called by other code modules. As discussed in detail below, by converting some or all of the input code into service tasks, various performance enhancement opportunities are provided.
[0081] Reference Figure 3 Each service task defined in the workflow module of the ConvertedParallelLoop class can be run whenever input data is available. In some cases, the runtime environment creates a single application process that runs the imperative bytecode together with the corresponding service task of the ConvertedParallelLoop class.
[0082] As noted, an application process can include multiple threads, each sharing a common address space. Each service task can run in a separate thread. Because the address space is shared, data shared by different service tasks does not need to be serialized or communicated over a network. In addition, because each service task can run in a separate thread, the service tasks can be scheduled independently of each other to accommodate any data dependencies between the service tasks. In this way, the order of operations defined in the input source code imposes fewer restrictions on the order in which the runtime executes the operations. Instead of executing the entire application as an imperative bytecode with numerous individual functions that must wait for other code modules to be invoked, the runtime environment can simply run each service task as long as the input data for that task is available.
[0083] In addition, the disclosed implementation allows for improvements in code orchestration. Traditionally, a given application may be scheduled to run in a single application process with or without multiple threads. Once the entire application process is running on a given machine, moving the application process to another machine may be very costly. In the disclosed implementation, individual service tasks may be moved to different application processes or different physical or virtual machines in a flexible manner. Although this may involve some serialization and network overhead, this flexibility may improve performance in some situations.
[0084] For example, consider a heterogeneous processing environment where a first virtual machine has access to high-performance hardware such as a field programmable gate array, while a second virtual machine has only a traditional central processing unit. Further, consider an application that has relatively lightweight service tasks in addition to specific service tasks that run very complex numerical operations, such as encryption tasks. Conventionally, the entire application may need to run in a single virtual machine. By converting the application into a data-independent service module, the encryption service tasks can be transferred to the virtual machine with high-performance hardware, while the remaining service tasks can be performed on the virtual machine that lacks these resources.
[0085] Example System
[0086] This implementation can be executed in various scenarios on various devices. Fig.13 An example system 1300 is shown in which the present implementations may be employed, as discussed in more detail below. Fig.13As shown in FIG. 1 , system 1300 includes client device 1310, server 1320, server 1330, and client device 1340 connected via one or more (multiple) networks 1350. Note that the client device can be embodied as a mobile device such as a smart phone or tablet computer, or as a fixed device such as a desktop computer. Similarly, various types of computing devices can be used to implement the server. In some cases, the server can be implemented in a data center, server farm, etc. Fig.13 Any device shown in , especially a server.
[0087] Fig.13 Certain components of the devices shown in may be referred to herein by reference numerals in parentheses. For purposes of the following description, parentheses (1) indicate that a given component is present on client device 1310, (2) indicates that a given component is present on server 1320, (3) indicates that it is present on server 1330, and (4) indicates that it is present on client device 1340. Unless a specific instance of a given component is identified, this document will generally refer to the component without parentheses.
[0088] Typically, devices 1310, 1320, 1330, and / or 1340 may have corresponding processing resources 1301 and storage resources 1302, which will be discussed in more detail below. These devices may also have various modules that use the processing and storage resources to perform the techniques discussed herein. For example, client device 1310 may include a code editor 1311, which may be used to edit code such as the C# code shown in the previous example. Code entered via the code editor may be provided to server 1320, which may execute development environment 1321. Typically, the development environment may implement Figure 1 The code conversion process flow 100 is shown in FIG.
[0089] Thereafter, the development environment 1321 may send the dependency graph 106, the imperative bytecode 122, and / or the service bytecode 124 to the server 1330. On the server 1330, the runtime environment 1002 may implement Fig.10 The runtime processing flow 1000 shown in FIG. 1000 can be a client device 1340 that can interact with the runtime via an interface module 1341 such as a local browser application, a smartphone application, or the like.
[0090] Example Source Code Transformation Method
[0091] Fig.14An example method 1400 that can be used to transform source code consistent with the present concepts is illustrated. As discussed more below, the method 1400 can be implemented on many different types of devices, for example, through one or more cloud servers, through a client device such as a laptop, tablet computer, or smart phone, or through a combination of one or more servers, client devices, etc. In some implementations, the method 1400 is performed by the development environment 1321.
[0092] The method 1400 begins at block 1402 where input source code is received. Figure 2 , Figure 4 , Figure 6 , Figure 8 and Fig.12 Each illustrates an example of an input source code.
[0093] Method 1400 continues at block 1404 where data dependencies are identified. Fig.11 Illustrated are several dependency graphs that can be used to represent data dependencies.
[0094] Method 1400 continues at block 1406 where an invariance point is identified. Fig.12 Invariance detection is discussed.
[0095] Method 1400 continues at block 1408 where the source code is converted. Examples of converted source code are provided above with reference to Figure 3 , Figure 5 , Figure 7 and Fig. 9 Discussion
[0096] Example runtime method
[0097] Fig.15 An example method 1500 that can be performed at runtime consistent with the present concepts is illustrated. As discussed further below, the method 1500 can be implemented on many different types of devices, for example, through one or more cloud servers, through a client device such as a laptop, tablet computer, or smart phone, or through a combination of one or more servers, client devices, etc. In some implementations, the method 1500 is performed by the runtime environment 1002.
[0098] Method 1500 begins at block 1502 where a service module and a partial dependency graph are obtained. Examples of service modules are described above with reference to Figure 3 , Figure 5 , Figure 7 and Fig. 9 A discussion was held.
[0099] Method 1500 continues at block 1504 where the service task is executed in the application process. The service task may be scheduled to run in the application process, as described above with reference to Fig.10 discussed.
[0100] Method 1500 continues at block 1506 where a specific runtime value is detected. Fig.11 As discussed, a runtime value such as a loop counter may be set to a final value by a service task or by imperative bytecode executing in runtime environment 1002 .
[0101] Method 1500 continues at block 1508 where the partial dependency graph is completed. For example, additional service tasks may be inserted into the partial dependency graph based on specific runtime values. Fig.11 In the example discussed, two additional service tasks are inserted into the partial dependency graph when the loop counter is completed at runtime.
[0102] The method 1500 continues at block 1508 where the additional service task is executed in the application process. For example, the additional service task may perform operations that were originally performed in the input source code by two additional loop iterations detected at runtime.
[0103] Further considerations
[0104] The discussion set forth above uses object-oriented source code examples to convey certain concepts. However, the disclosed techniques can be performed on other types of source code, including procedural programming languages as indicated. Additionally, while the above examples discuss bytecode generation as an example of source code conversion, some implementations may convert the input source code directly into a binary format that implements the above services.
[0105] In addition, please note that the source code examples set forth above provide specific examples of how certain operations may be converted into service modules. However, those skilled in the art will recognize that many other source code operations may be converted into service modules consistent with the present concept. For example, in some cases, the input source code may have conditional statements, such as if or switch statements. Broadly speaking, one method of converting such source code into service modules may involve duplicating the conditional statements in multiple service modules. By doing so, the original functionality of the input source code may be preserved.
[0106] Also, note that some implementations may combine individual service modules together to create a corresponding service. For example, consider a service module that does encryption and another service module that does decryption. These service modules can be logically combined into a single service that can be deployed together and replicated in different applications.
[0107] Because individual service modules are defined without cross-module data dependencies, they can be flexibly deployed at runtime. In some cases, services can be "hot deployed" at runtime by replacing deprecated service modules with newer versions. Typically, "hot deploying" a service module may involve inserting a new bytecode or binary version of the service module into the memory of a running process without having to stop the process.
[0108] In addition, because service modules are defined without cross-module data dependencies, they can be reused between different applications without rewriting. In this way, application developers can write source code with data dependencies between different library modules as they do when developing traditional libraries, and the code conversion process outputs data-independent service modules.
[0109] Device Implementation
[0110] As mentioned above about Fig.13 As noted, system 1300 includes several devices, including client device 1310, server 1320, server 1330, and client device 1340. It should also be noted that not all device implementations may be illustrated, and other device implementations should be apparent to the skilled person from the above and following descriptions.
[0111] As used herein, the terms "device," "computer," "computing device," "client device," and / or "server device" may refer to any type of device having a certain amount of hardware processing capability and / or hardware storage / memory capability. The processing capability may be provided by one or more hardware processors (e.g., hardware processing units / cores) that may execute computer-readable instructions to provide functionality. Computer-readable instructions and / or data may be stored on storage resources. The term "system," as used herein, may refer to a single device, multiple devices, and the like.
[0112] The storage resources may be internal or external to the respective devices with which they are associated. The storage resources may include any one or more of volatile or non-volatile memory, hard drives, flash memory devices, and / or optical storage devices (e.g., CDs, DVDs, etc.), etc. In some cases, the modules of the system 1300 are provided as executable instructions that are stored on a permanent storage device, loaded into a random access memory device, and read from the random access memory by a processing resource for execution.
[0113] As used herein, the term "computer-readable medium" may include signals. In contrast, the term "computer-readable storage medium" does not include signals. Computer-readable storage media include "computer-readable storage devices." Examples of computer-readable storage devices include volatile storage media such as RAM, and non-volatile storage media such as hard drives, optical disks, and flash memory.
[0114] In some cases, the device is configured with a general-purpose hardware processor and storage resources. In other cases, the device may include a system-on-chip (SOC) type design. In a SOC design implementation, the functions provided by the device can be integrated on a single SOC or multiple coupled SOCs. One or more associated processors can be configured to coordinate with shared resources such as memory, storage libraries, and / or with one or more dedicated resources such as hardware blocks configured to perform certain specific functions. In this way, the terms "processor", "hardware processor" or "hardware processing unit" used in this article may also refer to a central processing unit (CPU), a graphics processing unit (GPU), a controller, a microcontroller, a processor core, or other types of processing devices that are suitable for implementation in traditional computing architectures and SOC designs.
[0115] Alternatively or additionally, the functions described herein may be performed at least in part by one or more hardware logic components. For example, but not limited to, illustrative types of hardware logic components that may be used include field programmable gate arrays (FPGAs), application specific integrated circuits (ASICs), application specific standard products (ASSPs), systems on chip (SOCs), complex programmable logic devices (CPLDs), etc.
[0116] In some configurations, any module / code discussed herein may be implemented in software, hardware, and / or firmware. In any case, the module / code may be provided during the manufacturing process of the device, or provided by a middleman who is preparing to sell the device to an end user. In other instances, the end user may later install these modules / codes, such as by downloading an executable code and installing the executable code on a corresponding device.
[0117] Also note that a device can generally have input and / or output capabilities. For example, a computing device can have various input mechanisms, such as a keyboard, a mouse, a touchpad, voice recognition, gesture recognition (e.g., using a depth camera, such as a stereo or time-of-flight camera system, an infrared camera system, an RGB camera system, or using an accelerometer / gyroscope, facial recognition, etc.). A device can also have various output mechanisms, such as a printer, a monitor, etc.
[0118] It is also noted that the devices described herein can operate independently or in collaboration to implement the described techniques. For example, the methods and functions described herein can be executed on a single computing device and / or distributed across multiple computing devices that communicate via a network 1350. Without limitation, the network 1350 can include one or more local area networks (LANs), wide area networks (WANs), the Internet, etc.
[0119] In addition, some implementations may employ any disclosed technology in the context of the Internet of Things (IoT). In such an implementation, a home appliance or a car may provide computing resources that implement the system 1300 modules.
[0120] Various device examples are described above. Additional examples are described below. One example includes a method performed by a computing device, the method including receiving input source code, identifying data dependencies in the input source code, identifying invariant points in the input source code based at least on the data dependencies, and converting at least some of the input source code that appears after the invariant points into one or more service modules.
[0121] Another example may include any of the above and / or below examples, wherein identifying data dependencies includes constructing a graph having nodes and edges representing the data dependencies.
[0122] Another example may include any of the above and / or below examples, wherein the graph is a directed acyclic graph.
[0123] Another example may include any of the above and / or below examples, wherein the method further comprises compiling a portion of the input source code before the invariant point into imperative bytecode and compiling one or more service modules into service bytecode.
[0124] Another example may include any of the above and / or below examples, wherein the converting further comprises creating a service task to execute an instance of the one or more service modules.
[0125] A service task is created to execute an instance of one or more service modules, wherein the method further comprises identifying at least two service tasks that can be executed in parallel based at least on data dependencies and configuring the at least two service tasks to be executed in parallel at runtime.
[0126] Another example may include any of the above and / or below examples, wherein identifying the data dependency includes identifying at least one data item that is updated in only one iteration of a loop in the input source code.
[0127] Another example may include any of the above and / or below examples, wherein the method further comprises detecting, based at least on data dependency, that a particular service task depends on an output of another service task, and configuring the particular service task to wait for an output of the other service task at runtime.
[0128] Another example may include any of the above and / or below examples, wherein detecting data dependencies includes detecting at least one data item that is updated in multiple iterations of a loop in the input source code.
[0129] Another example includes a system comprising a hardware processing unit and a storage resource storing computer-readable instructions that, when executed by the hardware processing unit, cause the hardware processing unit to: receive input source code for an application, identify data dependencies in the input source code, identify invariant points in the input source code based at least on the data dependencies, convert at least a portion of the input source code that appears after the invariant points into one or more service modules, and schedule service tasks that execute the service modules at runtime consistent with the data dependencies.
[0130] Another example may include any of the above and / or below examples, wherein the computer-readable instructions, when executed by the hardware processing unit, cause the hardware processing unit to: access one or more execution logs reflecting previous executions of the service module, and schedule a service task based at least on the one or more execution logs.
[0131] Another example may include any of the above and / or below examples, wherein the computer readable instructions, when executed by a hardware processing unit, cause the hardware processing unit to: identify, based at least on data dependencies, an ordering constraint for executing the service task, and run the service task consistent with the identified ordering constraint.
[0132] Another example may include any of the above and / or below examples, wherein the computer readable instructions, when executed by the hardware processing unit, cause the hardware processing unit to run multiple service tasks in parallel in at least one instance as dictated by the ordering constraint.
[0133] Another example may include any of the above and / or below examples, wherein the computer readable instructions, when executed by a hardware processing unit, cause the hardware processing unit to sequentially execute a plurality of service tasks in at least one instance as indicated by an ordering constraint.
[0134] Another example may include any of the above and / or below examples, wherein the computer readable instructions, when executed by the hardware processing unit, cause the hardware processing unit to: compile a first portion of the input source code into imperative bytecodes, execute the imperative bytecodes to obtain result data, and provide the result data as input data to individual service tasks when available.
[0135] Another example may include any of the above and / or below examples, wherein the computer readable instructions, when executed by the hardware processing unit, cause the hardware processing unit to: output a workflow module related to the service task, and coordinate runtime communications between the service tasks according to the workflow module.
[0136] Another example includes a method performed by a computing device, the method comprising: obtaining a partial dependency graph of one or more service modules and service tasks for executing the one or more service modules, executing the service tasks in an application process, detecting a specific runtime value output by a specific service task, inserting one or more additional service tasks into the partial dependency graph based at least on the specific runtime value to obtain a completed dependency graph, and executing the one or more additional service tasks in the application process based at least on the completed dependency graph.
[0137] Another example may include any one of the above and / or following examples, wherein the method further includes: acquiring a workflow module that defines a service task, and executing the service task in an application process according to the workflow module.
[0138] Another example may include any of the above and / or below examples, wherein the method further comprises: identifying at least two additional service tasks that can run in parallel based at least on the completed dependency graph, and scheduling the at least two additional service tasks to run in parallel in the application process.
[0139] Another example may include any of the above and / or below examples, wherein the particular runtime value includes a loop counter.
[0140] in conclusion
[0141] Although the subject matter has been described in language specific to structural features and / or methodological acts, it should be understood that the subject matter defined in the appended claims is not necessarily limited to the specific features or acts described above. Instead, the specific features and acts described above are disclosed as example forms of implementing the claims, and other features and acts that those skilled in the art will recognize are intended to fall within the scope of the claims.
Claims
1. A method performed by a computing device, the method comprising: receiving input source code in an imperative programming style; identifying one or more data dependencies in the input source code; identifying, based at least on the one or more data dependencies, one or more invariant points in the input source code where one or more particular data items cease to be modified by the input source code; converting at least one instance of a specific function of the input source code into one or more service modules in a functional programming form, while retaining another instance of the specific function in the input source code in the imperative programming form, the at least one instance operating on the one or more specific data items and appearing in the input source code after the one or more invariant points; as well as Service tasks that execute the one or more service modules at runtime are scheduled consistent with the one or more data dependencies.
2. The method of claim 1 , wherein identifying the one or more data dependencies comprises: A graph is constructed having nodes and edges representing the one or more data dependencies. The method of claim 2 , wherein the graph is a directed acyclic graph.
4. The method according to claim 1, further comprising: determining that the another instance of the particular function operates on a local variable that is subsequently modified; as well as In response to determining that the other instance of the particular function operates on the local variable that is subsequently modified, retaining the other instance of the particular function in the imperative programming form.
5. The method according to claim 1, wherein the converting further comprises: A service task is created to execute an instance of the one or more service modules.
6. The method according to claim 5, further comprising: identifying at least two service tasks that can be run in parallel based at least on the one or more data dependencies; as well as The at least two service tasks are configured to be executed in parallel during runtime.
7. The method of claim 6, wherein the identifying the one or more data dependencies comprises: At least one data item that is updated in only one iteration of a loop in the input source code is identified.
8. The method according to claim 5, further comprising: detecting, based at least on the one or more data dependencies, that a particular service task is dependent on an output of another service task; as well as The specific service task is configured to wait for the output of the other service task during execution.
9. The method of claim 8, wherein the identifying the one or more data dependencies comprises: At least one data item that is updated in a plurality of iterations of a loop in the input source code is detected.
10. A system comprising: Hardware processing unit; as well as a storage resource storing computer readable instructions that, when executed by the hardware processing unit, cause the hardware processing unit to: receiving input source code for an application, the input source code being received in an imperative programming form; identifying one or more data dependencies in the input source code; identifying, based at least on the one or more data dependencies, invariant points in the input source code where one or more particular data items cease to be modified by the input source code; For a specific variable operated by a first instance of a specific function, converting the first instance of the specific function that appears in the input source code after a specific invariant point into one or more service modules in the functional programming form, while retaining a second instance of the specific function in the input source code in the imperative programming form; as well as Service tasks that execute the one or more service modules at runtime are scheduled consistent with the one or more data dependencies.
11. The system of claim 10, wherein the computer readable instructions, when executed by the hardware processing unit, cause the hardware processing unit to: accessing one or more execution logs reflecting previous executions of the one or more service modules; and The service task is scheduled based at least on the one or more execution logs.
12. The system of claim 10, wherein the computer readable instructions, when executed by the hardware processing unit, cause the hardware processing unit to: identifying, based at least on the one or more data dependencies, an ordering constraint for executing the service task; and The service tasks are executed consistent with the identified ordering constraints.
13. The system of claim 12, wherein the computer readable instructions, when executed by the hardware processing unit, cause the hardware processing unit to: In at least one instance, a plurality of service tasks are executed in parallel as dictated by the ordering constraints.
14. The system of claim 12, wherein the computer readable instructions, when executed by the hardware processing unit, cause the hardware processing unit to: In at least one instance, a plurality of service tasks are executed serially as dictated by the ordering constraints.
15. The system of claim 10, wherein the computer readable instructions, when executed by the hardware processing unit, cause the hardware processing unit to: compiling a portion of the input source code into imperative bytecode; executing the imperative bytecode to obtain result data; and When available, the result data are provided as input data to the individual service tasks.
16. The system of claim 10, wherein the computer readable instructions, when executed by the hardware processing unit, cause the hardware processing unit to: Outputting a workflow module related to the service task; and Runtime communication between the service tasks is coordinated according to the workflow module.
17. A method performed by a computing device, the method comprising: obtaining a first instance of a specific function in an imperative form, a second instance of the specific function converted to one or more service modules in a functional programming form, and a partial dependency graph for executing service tasks of the one or more service modules, the one or more service modules having been converted from a portion of source code, wherein the portion appears in the source code after one or more invariant points, wherein one or more specific data items operated by the second instance of the specific function cease to be modified by the source code; Execute the first instance of the specific function and the service task in an application process; Detecting specific runtime values output by specific service tasks; inserting one or more additional service tasks into the partial dependency graph to obtain a completed dependency graph based at least on the specific runtime value; as well as Based at least on the completed dependency graph, the one or more additional service tasks are performed in the application process.
18. The method according to claim 17, further comprising: Obtain a workflow module that defines the service task; as well as The service task is executed in the application process according to the workflow module.
19. The method according to claim 17, further comprising: Based at least on the completed dependency graph, identifying at least two additional service tasks that can be run in parallel; as well as The at least two additional service tasks are scheduled to run in parallel in the application process.
20. The method of claim 19, wherein the specific runtime value comprises a cycle counter.
Citation Information
Patent Citations
Field specialization systems and methods for improving program performance
CN107851003A
Protecting a web server against an unauthorized client application
CN109891415A