[]
异步函数是指任何以非阻塞方式异步或并发地交付其结果的函数。异步函数具有非阻塞性架构,这意味着一个任务的执行并不依赖于另一个任务。任务可以同时运行。通过允许多个计算同时进行,运行异步函数可以提升性能。GcExcel(假设这是某个Excel插件或扩展的名称)通过从 AsyncCustomFunction 类派生函数来使函数能够进行异步计算。evaluateAsync 方法用于异步计算该函数。GcExcel 还在CalcError 枚举中提供了一个枚举值“Busy”,这表明单元格正在计算异步公式。
下面是一个添加和使用自定义异步函数的示例代码:
public class AsyncFunction {
public static void main(String[] args) {
// Register Async custom function.
Workbook.AddCustomFunction(new MyAddFunction());
// Implement the Async custom Function.
Workbook workbook = new Workbook();
IWorksheet worksheet = workbook.getWorksheets().get(0);
worksheet.getRange("A1").setValue(1);
worksheet.getRange("B1").setValue(2);
// Add the cell values.
worksheet.getRange("C1").setFormula("=MyAdd(A1,B1)");
Object value1 = worksheet.getRange("C1").getValue();
// Display result. The result will be "Busy".
System.out.println(value1);
Thread.sleep(2000);
Object value2 = worksheet.getRange("C1").getValue();
// Display result. The result will be "3".
System.out.println(value2);
}
}
// Define Async custom function: MyAddFunction.
class MyAddFunction extends AsyncCustomFunction {
public MyAddFunction() {
super("MyAdd", FunctionValueType.Number, new Parameter[] { new Parameter(FunctionValueType.Number), new Parameter(FunctionValueType.Number) });
}
@Override
public CompletableFuture<Object> evaluateAsync(Object[] arguments, ICalcContext context) {
return CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
}
return (double)arguments[0] + (double)arguments[1];
});
}
}
限制:
type=danger
AsyncCustomFunction 的参数不接受任何引用类型,因为异步函数可能会在另一个线程中运行,如果你使用引用,这会导致多线程冲突。同样,在异步函数内部不允许使用如 IWorksheet 和 IWorkbook 这样的对象。
GcExcel 支持异步的 IMAGE 公式函数,允许你从 URL 路径向单元格中添加图片。它提供了 alt_text、sizing、height 和 width 等参数来设置替代文本、图片大小、高度和宽度。这个函数的 source 参数允许你使用 “https” 协议提供图片的URL路径。为了处理这个网络请求,GcExcel 提供了 Workbook 类的 setWebRequestHandler 方法,使你能够访问和自定义应用程序的网络请求处理器。 setWebRequestHandler 方法是 IWebRequestHandler 接口类型的,这个接口定义了处理网络请求的方式,并提供了一种向指定 URI 发送 GET 请求的方法。
异步函数以非阻塞方式异步或并发地交付结果,但有些操作依赖于其他函数的计算结果。GcExcel 提供了 IWorkbook 接口的 waitForCalculationToFinish 方法,确保在继续依赖计算结果的任何其他操作之前,所有的必要计算都已完成。它会等待所有计算完成,包括异步计算。这个方法会阻塞当前线程直到所有计算完成。
以下是添加和使用异步 IMAGE 函数的示例代码:
public class AsyncImageFunction {
public static void main(String[] args) throws Exception {
// Set a custom web request handling class to send all network requests.
Workbook.setWebRequestHandler(new WebRequestHandler());
// Initialize Workbook.
Workbook workbook = new Workbook();
// Get the active sheet.
IWorksheet sheet = workbook.getActiveSheet();
// Set IMAGE function.
IRange range = sheet.getRange("A1:F10");
range.setFormula("=IMAGE(\"https://support.content.office.net/en-us/media/926439a2-bc79-4b8b-9205-60892650e5d3.jpg\")");
// Calculate all formulas so the asynchronous image function will run.
workbook.calculate();
// Block the current thread until all asynchronous functions have finished to avoid #BUSY! error in the exported file.
workbook.waitForCalculationToFinish();
// Save the workbook.
workbook.save("AsyncImageFunction.pdf");
workbook.save("AsyncImageFunction.xlsx");
}
}
//Create custom web request handling class.
class WebRequestHandler implements IWebRequestHandler {
@Override
public CompletableFuture<WebRequestResult> getAsync(String requestUri) {
WebRequestResult result = new WebRequestResult();
return CompletableFuture.supplyAsync(() -> {
try {
URL url = new URL(requestUri);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
int responseCode = connection.getResponseCode();
result.setStatusCode(responseCode);
if (responseCode >= 200 && responseCode < 300) {
result.setResponseContent(toByteArray(connection.getInputStream()));
} else {
System.out.println("Request failed with status code: " + responseCode);
}
} catch (IOException e) {
result.setConnectionFailed(true);
}
return result;
});
}
public byte[] toByteArray(InputStream inputStream) {
try (ByteArrayOutputStream output = new ByteArrayOutputStream()) {
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) != -1) {
output.write(buffer, 0, bytesRead);
}
return output.toByteArray();
} catch (IOException e) {
throw new RuntimeException("Error converting InputStream to byte array", e);
}
}
}